Unfinished caving discovered in Mockito

While testing, I get the following exception. I use mockito for ridicule. The recommendations mentioned in the Mockito library do not help.

org.mockito.exceptions.misusing.UnfinishedStubbingException: Unfinished stubbing detected here: -> at com.abDomainTestFactory.myTest(DomainTestFactory.java:355) Eg 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! at abDomainTestFactory.myTest(DomainTestFactory.java:276) .......... 

Test code from DomainTestFactory. When I run the next test, I see an exception

 @Test public myTest(){ MyMainModel mainModel = Mockito.mock(MyMainModel.class); Mockito.when(mainModel.getList()).thenReturn(getSomeList()); --> Line 355 } private List<SomeModel> getSomeList() { SomeModel model = Mockito.mock(SomeModel.class); Mockito.when(model.getName()).thenReturn("SomeName"); --> Line 276 Mockito.when(model.getAddress()).thenReturn("Address"); return Arrays.asList(model); } public class SomeModel extends SomeInputModel{ protected String address; protected List<SomeClass> properties; public SomeModel() { this.Properties = new java.util.ArrayList<SomeClass>(); } public String getAddress() { return this.address; } } public class SomeInputModel{ public NetworkInputModel() { this.Properties = new java.util.ArrayList<SomeClass>(); } protected String Name; protected List<SomeClass> properties; public String getName() { return this.Name; } public void setName(String value) { this.Name = value; } } 
+124
java mockito mocking
Oct 11 '14 at 19:42
source share
1 answer

You nestled in mockery. You call getSomeList() , which taunts you a bit before you finish the mockery of MyMainModel . Mockito doesn't like it when you do it.

Replace

 @Test public myTest(){ MyMainModel mainModel = Mockito.mock(MyMainModel.class); Mockito.when(mainModel.getList()).thenReturn(getSomeList()); --> Line 355 } 

from

 @Test public myTest(){ MyMainModel mainModel = Mockito.mock(MyMainModel.class); List<SomeModel> someModelList = getSomeList(); Mockito.when(mainModel.getList()).thenReturn(someModelList); } 

To understand why this is causing the problem, you need to know a little about how Mockito works, and also to know in what order expressions and expressions are expressed in Java.

Mockito cannot read your source code, so it relies heavily on static state to find out what you are asking it to do. When you call a method on the object’s layout, Mockito writes the details of the call to the internal call list. The when method reads the last of these extracts from the list and records this call in the returned OngoingStubbing object.

Line

 Mockito.when(mainModel.getList()).thenReturn(someModelList); 

causes the following interactions with Mockito:

  • The mock method is called mainModel.getList() ,
  • The static when method is called,
  • The thenReturn method thenReturn called on the OngoingStubbing object returned by the when method.

The thenReturn method can then instruct the layout obtained by it with the OngoingStubbing method to handle any suitable call to the getList method to return someModelList .

In fact, since Mockito cannot see your code, you can also write your mockery as follows:

 mainModel.getList(); Mockito.when((List<SomeModel>)null).thenReturn(someModelList); 

This style is somewhat less readable, especially since in this case null must be started, but it generates the same sequence of interactions with Mockito and achieves the same result as the line above.

However line

 Mockito.when(mainModel.getList()).thenReturn(getSomeList()); 

causes the following interactions with Mockito:

  • The mock method is called mainModel.getList() ,
  • The static when method is called,
  • A new mock of SomeModel (inside getSomeList() ),
  • The mock model.getName() method is model.getName() ,

At this point, Mockito was confused. He thought you were mocking mainModel.getList() , but now you say you want to mock the model.getName() method. For Mockito, it looks like you are doing the following:

 when(mainModel.getList()); // ... when(model.getName()).thenReturn(...); 

This looks silly to Mockito , as he cannot be sure what you are doing with mainModel.getList() .

Note that we did not receive a call to the thenReturn method, since the JVM must evaluate the parameters of this method before it can call the method. In this case, this means calling the getSomeList() method.

As a rule, this is a poor design decision to rely on a static state, as Mokito does, because this can lead to the principle of least surprise being violated. However, the design of Mockito makes a clear and expressive mockery, even if it sometimes leads to amazement.

Finally, recent versions of Mockito add an extra line to the error message above. This additional line indicates that you may be in the same situation as this question:

3: you end the behavior of another layout inside before the thenReturn command, if completed

+309
Oct 11 '14 at 21:19
source share



All Articles