1

I am facing a strange problem while trying to unit test my code.

Here is my code :

public class ItemService {

    private OfferService offerService;

    @Inject
    public ItemService (OfferService offerService){
        this.offerService = offerService;
    }

    public List<Item> buildItems(ItemInfo itemInfo) {
        List<Item> items = processItem(itemInfo);
        Offers<Offer> offers = fetchItemInfo(items);

        // based on the object offers, do some processing
    }


    private Offers<Offer> fetchItemInfo(List<Item> items) {
            Offers<Offer> offers = new Offers<>();
            // some processing here with offers.
            // calling the db to fetch details 
            offerService.fetchInfoFromDB(offers);
            return offers;
    }
}

public class OfferService {
    public void fetchInfoFromDB(Offers<Offer> offers) {
        // fetching details from DB
        // and updating the object **offers**
        myDao.getDetailsById(id);
    }
}

Now I have written junit to test the method buildItems()

UPDATE updating the mocks used and mock injection.

@RunWith(PowerMockRunner.class)
@PrepareForTest(ItemService.class)
public class ItemServiceTest{

    @Mock private MyDAO myDao;
    @Mock private OfferService offerService;

    @Before
    public void setUp() throws Exception {
        ItemService  itemService = new ItemService (offerService, myDao);

    }

    public void testBuildItems(){
        // some code -----
        itemInfo = buildItemInfo();
        offerDetail = buildOfferDetail();
        when(myDao.getDetailsById(Mockito.anyLong())).thenReturn(offerDetail);

        // some code -----
        // I need to implement some code which will actually call
        // offerService.fetchInfoFromDB(offers);
        // and update the --offers-- object and return it.
        List<Item> items = itemService.buildItems(itemInfo);
        Assert.assertNotNull(items);
    }
    
}

I am running with coverage and I can see that the below line got executed but the actual method is not getting called :

offerService.fetchInfoFromDB(offers);

I am getting null values in offers. Then I added the below line :

doCallRealMethod().when(offerService).fetchInfoFromDB(offers);

Still the same result. The offers object is passed by reference and is getting updated after the DB call which I am mocking already. But upto that call my code is not reaching. How can I update the offers object in my junit. Please help.

Som
  • 1,522
  • 1
  • 15
  • 48
  • @JeffBowman : Can you please help. Got to you through this post : https://stackoverflow.com/questions/27421417/modify-input-parameter-of-a-void-function-and-read-it-afterwards/27432585 – Som Nov 26 '21 at 14:00
  • Comment replies by name [only notify with users who interact with the post](https://meta.stackexchange.com/questions/43019/how-do-comment-replies-work). Mentioning me by name doesn't work unless I've already posted here. Your comment on my question did work, but asking a specific user for help is [not appropriate behavior on StackOverflow](https://meta.stackoverflow.com/questions/255669/is-it-ethical-to-contact-a-user-to-draw-their-attention-to-a-question-where-the). Finally, you can edit my other question into the body text here; it helps answerers to know what you've seen and tried. – Jeff Bowman Nov 26 '21 at 14:14
  • As Deb Das noted, you haven't actually shown us your test setup where you populate `itemService.offerService` with a mock OfferService, and in fact your mock in your test is `myDao` rather than any Service at all. Without that additional context, I don't think there is enough information here to diagnose your problem. – Jeff Bowman Nov 26 '21 at 14:17
  • @JeffBowman : Hi .. Thanks for replying. I have updated the mocks in my test class. Can you check now please. Even though `offerService` I am mocking but I cant use it properly. – Som Nov 26 '21 at 14:30
  • Can you please tell what your `List items = processItem(itemInfo)` returning while you debug? Secondly offerService is a dependency in the class but i dont see it being injected or initialized. – Deb Das Nov 26 '21 at 09:33

1 Answers1

2

Your test is calling a zero arg ItemService() constructor, not the one arg @Inject constructor you posted. Either your code won't compile, or you haven't actually shown us the code in question.

Also, you say you are mocking offerService:

  1. You call when on myDao and not offerService,

  2. you do not pass your mock offerService into your ItemService constructor, as in new ItemService(offerService), and

  3. your doCallRealMethod won't work because your mock offerService won't use your mock myDao; you'll need to mock the call on offerService directly with a thenAnswer that changes the passed List<Offer>, as on my question you linked.

     doAnswer(invocation -> {
        ((List<Offer>) invocation.getArgument(0)).add(offerDetail);
        return null;
     }).when(offerService).fetchInfoFromDb(any());
    

If you fix those three you will be considerably closer to a working test.

Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
  • I am not using zero arg . Its initializing the required fields. I was not able to call `when` on `offerService` as it was not returning anything. Only the object was getting updated based on some validations. Now what I am doing is trying to mock the private method call `fetchItemInfo` using PowerMockito and I could control the object. My purpose is solved. But still I am unable to use the `doAnswer` or `thenAnswer`. Can you help me in that please as I dont want to mock private methods. – Som Nov 27 '21 at 08:24
  • Also I dont want to test the method `fetchItemInfo()`. I want to test the method `buildItems()` which needs the output from `fetchItemInfo()` as based on that output I have different scenarios to test. – Som Nov 27 '21 at 08:41
  • 1
    @Som Thank you for updating your constructor to be more accurate. You are right to avoid mocking `fetchItemInfo`, not just because it is a private method, but also because it is a part of your system under test. I'll update with a `doAnswer` attempt, but you may need to correct it, as I am not at a proper computer to test. – Jeff Bowman Nov 27 '21 at 08:47
  • Thanks a lot ! let me try it out .. I will let you know surely. – Som Nov 27 '21 at 12:43