Suppose I have 3 classes, ClassA which contains a ClassB which contains a ClassC. I'm trying to test a method inside ClassA, that method needs to call ClassB to get the instance of ClassC and execute a VOID method inside ClassC (I know this wrong, cause ClassA should not be aware of ClassC, code smell, this is not my code and just trying to create a test of it). However when I try to skip that method call using Mockito.doNothing I get the following error:
org.mockito.exceptions.misusing.UnfinishedStubbingException:
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, you naughty developer!
3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed
Here's the code:
ClassA:
public class ClassA {
private ClassB classB;
public ClassA(ClassB classB) {
this.classB = classB;
}
public void methodToTest() {
classB.getClassC().someVoidMethod("123");
}
}
ClassB:
public class ClassB {
private ClassC classC;
public ClassB(ClassC classC) {
this.classC = classC;
}
public ClassC getClassC() {
return classC;
}
}
ClassC:
public class ClassC {
public void someVoidMethod(String arg) {
System.out.println(arg);
}
}
Test Class
@RunWith(MockitoJUnitRunner.class)
public class ClassATest {
@InjectMocks
private ClassA classA;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private ClassB classB;
@Mock
private ClassC classC;
@Test
public void test() {
Mockito.doNothing().when(classB.getClassC()).someVoidMethod("123");
}
}
Once again, this code is not mine so I can't modify the way it uses the dependencies. I'm just trying to test it.
Quick Note: Mockito.when(...).thenReturn(...) works fine, but this is not my case since the method I'm trying to Mock is void.
I think this works. I am not sure why you can't use classB.getClassC()
instead of referencing classC
directly.
@RunWith(MockitoJUnitRunner.class)
public class ClassATest {
@InjectMocks
private ClassA classA;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private ClassB classB;
@Mock
private ClassC classC;
@Before
public void init() {
doReturn(classC).when(classB).getClassC();
doNothing().when(classC).someVoidMethod("123");
}
@Test
public void test() {
classA.methodToTest();
}
}
Your mocking syntax is improperly arranged.
Mockito.doNothing().when(classB.getClassC()).someVoidMethod("123");
When you add spaces to this statement to individual pieces it is apparent.
Mockito response method method
Mockito .doNothing() .when(classB.getClassC()) .someVoidMethod("123");
When you pass a METHOD to when, it expects a thenReturn
When you pass an OBJECT to when, then you can chain a void method from that.
Mockito.when(classB.getClassC()).thenReturn(classC);
Mockito.doNothing().when(classC).someVoidMethod("123");
The reason this doesn't work like you think it does is because classB.getClassC()
doesn't work like a getter when passed through when()
.
You're not actually passing a reference to the object to Mockito, but a method that Mockito will stub for you with thenReturn
, which it complains is missing because you don't have one.
tl:dr;
Do not treat mock object methods like actual methods within mockito stubbing code.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.