0

I am failing to write a Test because the answer of my when().thanReturn() is not returning anything. I am not able to mock the behavior (Setup is Spring Boot, Java 8, Junit 4). The problem is that the Method being called is taking method References as a parameters:

List<PubSubMessage> findMessages(DateCheckerPredicate whichDateFunction, MessageRepoPredicate whichQueryToUse, int tableId) {
List<PubSubMessage> rulesToPublish = new ArrayList<>();
    List<Object> queryResult = whichQueryToUse.findObjects(tableName);
    if(queryResult != null) {
        queryResult.forEach(object -> {
            if(whichDateFunction.checkDates(object)) {
                rulesToPublish.add(new PubSubMessage(tableId, object.getId()));
            }
        });
    }
    return rulesToPublish;
}

Calling the method looks something like this:

public void methodToTest {
   List<PubSubMessage> messages = dao.findMessages(MessageDateChecker::msgCanBePublished, msgRepo::findMsgesToPublish, tableId);
}

where MessageDateChecker uses static "helper Methods" and msgRepo is a class which is annotated with Springs @Service and using jdbcTemplates to query the DB. And the class looks something like this:

private Dao dao;
private MsgRepo msgRepo;
@Autowired
public SomeService(Dao dao, MsgRepo msgRepo) {
   this.dao = dao;
   this.msgRepo = msgRepo;
}

The test setup looks something like this:

@Mock
private Dao dao;
@Mock
private MsgRepo msgRepo;
@InjectMock
public SomeService(dao, msgRepo)
private int tableId = 1;
private String tableName = "someTableName";


@Test
public void someTest() {
    List<PubSubMessage> list = new ArrayList<>();
    list.add(new PubSubMessage(tableId, 12));
    List<Object> objects = new ArrayList<>();
    objects.add(new Object(12, new Date(), null));
    when(dao.findMessages(MessageDateChecker::msgCanBePublished, msgRepo::findMessagesToActivate, tableId)).thenReturn(list);

   someService.methodToTest() //in here findRules is getting called()

   verify(someClass,times(1)).someMethod()
}

Like I mentioned above the when().thanReturn() should return the predefined list but when running the test, it always returns null. Does anyone can provide some help? Probably I need to do a better job mocking the method-references which are being passed at a parameter. But So far I am failing to do it right.

podoi17
  • 39
  • 9

2 Answers2

1

The parameter values being passed while mocking dao.findMessages(), should be the same as the values when the method is called inside someService.methodToTest(). Else you can use ArgumentsMatcher.any(). Personally I prefer to evaluate what will come there and then pass the same args while mocking.

Dharman
  • 30,962
  • 25
  • 85
  • 135
saurabh kedia
  • 321
  • 2
  • 11
  • Thanks for the answer, I actually thought that I am doing that. Can you tell from what I posted where I am wrong for this approach? – podoi17 Jul 29 '20 at 11:49
  • 1
    While mocking dao.findMessages you are calling the method of a mock object msgRepo::findMessagesToActivate . Try mocking this method as well. – – saurabh kedia Jul 29 '20 at 12:45
  • Its still failing. For now the solution with the ArgumentMatcher works since the test is just to verify several Method calls. I know would be a cleaner way to get the test running with the correct Arguments. – podoi17 Jul 29 '20 at 12:48
  • Maybe you can try running it in debug mode, put a breakpoint where the method `dao.findMessages` is being called. You can check the values of the arguments being passed and then try to mimic the same for your method – saurabh kedia Jul 29 '20 at 12:58
  • the first argument is a static call, and the second one is of the same type msgRepo; which in the test case mockito mocked :/ – podoi17 Jul 29 '20 at 13:54
  • what this method does? `MessageDateChecker::msgCanBePublished`. Pass the mock value of `msgRepo::findMessagesToActivate` directly when you'r emocking `dao.findMessages` instead of calling the method as argument – saurabh kedia Jul 29 '20 at 14:48
1

As I wrote in my comment, just use any() as in

when(dao.findMessages(any(), any(), eq(tableId))).thenReturn(list);

The problem is that if you pass something like SomeClass::someMethod, this creates an intermediate object that implements the expected functional interface. If you do the same in the test code, another object will be created, so the matcher will not regard them as the same.

daniu
  • 14,137
  • 4
  • 32
  • 53