5

I have method:

public void loadPlatformDependencies() {
    try {
        dependenciesRepository.deleteAll();
        dependenciesRepository.saveAll(pullLastDependencies());
        publisher.publishEvent(new LoadedDependenciesEvent());
    } catch (Exception e) {
        LOGGER.error("Failed to load dependencies", e);
    }
}

And I try to test it:

   @Test
    public void testLoadPlatformDependencies() {
        ArgumentCaptor<Iterable<Dependency>> captor = ArgumentCaptor.forClass(Iterable.class);
        when(dependenciesRepository.saveAll(captor.capture())).thenReturn(any(Iterable.class));
        puller.loadPlatformDependencies();

        verify(dependenciesRepository,times(1)).deleteAll();
        verify(dependenciesRepository, times(1)).saveAll(any(Iterable.class));
        verify(publisher,times(1)).publishEvent(any());

   }

But there is a problem, that method pullLastDependencies() work incorect now. I have a mistake:

Invalid use of argument matchers!
0 matchers expectd, 1 recorded:

Method pullLastDependencies() returns List. Can I test this method without a properly working method pullLastDependencies()? Or maybe I should test this method in another way?

petrov.aleksandr
  • 622
  • 1
  • 5
  • 24
  • Does this answer your question? [How do Mockito matchers work?](https://stackoverflow.com/questions/22822512/how-do-mockito-matchers-work) – second Dec 21 '19 at 13:08
  • Main part of my question is how to test it, if pullLastDependencies() is private method that can't work now – petrov.aleksandr Dec 21 '19 at 13:12

2 Answers2

2

You're using the captor in when() instead of verify(). And you're returning any() (which is just null) from your mocked method, instead of returning what you want this mock to return. if you don't care about what it returns because you don't use it, then return an empty iterable.

It should be

when(dependenciesRepository.saveAll(any()).thenReturn(Collections.emptyList());
puller.loadPlatformDependencies();

verify(dependenciesRepository).deleteAll();
verify(dependenciesRepository).saveAll(captor.capture());
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • method saveAll(), in arguments invokes another method: pullLastDependencies(), that throw NullPointerException. Can I test it without of invoking this method(pullLastDependencies())? – petrov.aleksandr Dec 21 '19 at 13:22
  • 1
    @petrov No, unless you can mock pullLastDependencies(). If it throws an NPE, then analyze the stack trace to know what is null, and fix the code or the test accordingly. – JB Nizet Dec 21 '19 at 13:25
  • It throws NPE because it has no connection now and some logic of this method is mocked. But it works, is it possible to mock private metrod? – petrov.aleksandr Dec 21 '19 at 13:30
  • 2
    No, it's not possible. I don't know what you're talking about since you didn't post the code. If "it has no connection" then you probably need to mock that connection, or the object providing the connection. Or to refactor the code and put that method in a separated, injected object that you can mock. – JB Nizet Dec 21 '19 at 13:33
-1

I think the problem here is that you are using a matcher as a return value in

when(dependenciesRepository.saveAll(captor.capture())).thenReturn(any(Iterable.class));

You should use the matchers to "match" method parameters, and return another structure, like this:

when(dependenciesRepository.saveAll(anyIterable())).thenReturn(Collections.emptyList())

As long as your pullLastDependencies() method doesn't have another dependency, it should work.

Edit: It seems that your pullLastDependencies() has some other dependencies, so you need to mock the call to it. You can achieve this by changing the visibility of the method during the test, so you can mock it, but keep in mind that this is not considered good pratice.

//making private method accessible
Method method = service.getClass().getDeclaredMethod("pullLastDependencies",params);
method .setAccessible(true); 
when(pullLastDependencies()).thenReturn(Collections.emptyList())
fred7
  • 9
  • 7
  • But problem is that pullLastDependencies() invoke another private methods. And if i want test it, should I test all logic from private methods? – petrov.aleksandr Dec 21 '19 at 13:52
  • See updated answer, maybe you can try changing the visibility thru reflection – fred7 Dec 21 '19 at 13:56
  • Don't reflectively hack and mock out methods in the class under test... This is terrible practice. So your test for "load platform dependencies" tests you save something but doesn't care at all what it is it's saving? You don't care that `pullLastDependencies()` may not work at all? This type of testing may make it look like you're testing lots of the functionality but what you're really doing is putting junk tests in that scratch the surface where it's easy and ignore the real meat of your implementation. – John Stringer Dec 21 '19 at 16:42
  • 2
    And if there's totally no way of testing the `pullLastDependencies()` method, stick an interface in-front of it and mock that out, don't go down the reflection route. There are good uses of reflection but lots of places where people opt to use it, like here is just hacky. – John Stringer Dec 21 '19 at 16:45