I have a void method bar
in a service Foo
as shown:
@Component
@EnableAsync
@AllArgsConstructor
public class Foo {
private final SomeOtherService someOtherService;
private final KafkaListenerEndpointRegistry registry;
private final FooConfig fooConfig;
@Async("myExecutor")
public void bar(A a, B b, ConcurrentSkipListMap<Long, String> c, int d, int e) {
someOtherService.doSomething(a, b, c, d, e);
}
}
I am using Foo
in MyService
class,
@Service
@AllArgsConstructor
public class MyService {
private final Foo foo;
public void execute() {
// call foo.bar();
}
}
Now, I am trying to write a unit test for a case when calling foo.bar()
can throw a RuntimeException. Here is my test class:
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer;
import java.util.concurrent.ConcurrentSkipListMap;
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {SpringBootMain.class},
initializers = {ConfigDataApplicationContextInitializer.class})
@TestPropertySource(properties = {"spring.config.location=classpath:application-test.yml"})
public class MyServiceTest {
@MockBean
private SomeOtherService someOtherService;
@SpyBean
@Autowired
private Foo foo;
@Test
public void test() {
MyService myService = new MyService(foo);
Mockito.doThrow(new RuntimeException("failed")).when(foo).bar(any(A.class), any(B.class), any(ConcurrentSkipListMap.class), anyInt(), anyInt());
myService.execute();
// some assertions
}
}
But I am getting this error while running the test:
WARN org.springframework.test.context.TestContextManager --
Caught exception while invoking 'afterTestMethod' callback on TestExecutionListener [org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener]
for test method [public void MyServiceTest.test() throws com.fasterxml.jackson.core.JsonProcessingException]
and test instance [MyServiceTest@60fc4450]
org.mockito.exceptions.misusing.UnfinishedStubbingException: Unfinished stubbing detected
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, which is not supported
3. you are stubbing the behaviour of another mock inside before 'thenReturn' instruction is completed
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
1 matchers expected, 5 recorded:
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(any(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(any(), eq("String by matcher"));
For more info see javadoc for Matchers class.
I have tried other configurations as well including:
Mockito.doThrow(new RuntimeException("failed")).when(foo).bar(any(A.class), any(B.class), Mockito.<ConcurrentSkipListMap<Long, String>>any(), anyInt(), anyInt());
Mockito.doAnswer(inv -> {
throw new RuntimeException("failed");
}).when(foo).bar(Mockito.any(A.class),
Mockito.any(B.class),
Mockito.any(ConcurrentSkipListMap.class),
Mockito.anyInt(),
Mockito.anyInt());
But nothing worked so far. Any help is appreciated.
While I can't figure out the mistake in your code since several classes are involved, I can provide you with a solution with imports that works. It may help you.
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import java.util.concurrent.ConcurrentSkipListMap;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import so.A;
import so.B;
import so.Foo;
import so.MyService;
import so.SomeOtherService;
@ExtendWith(SpringExtension.class)
@TestPropertySource(properties = { "spring.config.location=classpath:application-test.yml" })
public class MyServiceTest {
@MockBean
private SomeOtherService someOtherService;
@SpyBean
@Autowired
private Foo foo;
@Test
public void test() {
MyService myService = new MyService(foo);
Mockito.doThrow(new RuntimeException("failed")).when(foo).bar(any(A.class), any(B.class),
any(ConcurrentSkipListMap.class), anyInt(), anyInt());
myService.execute();
// some assertions
}
}
Here are the dummy classes that I created that was not part of your question:
public class A {}
public class B {}
public class SomeOtherService {
public void doSomething(A a, B b, ConcurrentSkipListMap<Long, String> c, int d, int e) {
}
}