Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mockito UnfinishedStubbingException

Tags:

java

mockito

I am new to Mockito, I have tried looking into this Exception but I haven´t found a concrete answer. It happens in my code when I use two mocks together, meaning that I give through the constructor of a mock, another mock. Like so:

...
OperationNode child = getNode(Operation.ADD);
child.insertNode(getConstantNode(getIntegerValue(2));
...

 private ConstantNode getConstantNode(NumericalValue value){
    ConstantNode node = Mockito.mock(ConstantNode.class);
    Mockito.when(node.evaluate()).thenReturn(value);
    Mockito.when(node.toString()).thenReturn(value.toString());
    return node;
}

private IntegerValue getIntegerValue(int number) {
   IntegerValue integerValue = Mockito.mock(IntegerValue.class);
   Mockito.when(integerValue.getValue()).thenReturn(number);
   Mockito.when(integerValue.toString()).thenReturn(Integer.toString(number));
   return integerValue;
}

In one of the forums I read about not sending a mock through a constructor of another mock, since Mockito might get confused with the mock calls, so I tried the following:

NumericalValue value = getIntegerValue(2);
child.insertNode(getConstantNode(value));

But to no avail. I make sure that only the methods toString() and getValue() are called, because those are the only methods the class has. I don´t understand what´s going on.

I have also tried using the mocks separately, to see if I have done something wrong:

child.insertNode(new ConstantNode(getIntegerValue(2)));

That works perfectly.

child.insertNode(getConstantNode(new IntegerValue(2)));

That works fine too.

like image 913
Chayemor Avatar asked Mar 21 '13 17:03

Chayemor


People also ask

What is unfinished stubbing exception?

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.

What is the difference between doReturn and thenReturn?

Following are the differences between thenReturn and doReturn : * Type safety : doReturn takes Object parameter, unlike thenReturn . Hence there is no type check in doReturn at compile time. In the case of thenReturn , whenever the type mismatches during runtime, the WrongTypeOfReturnValue exception is raised.

What is doReturn in Mockito?

You can use doReturn-when to specify a return value on a spied object without making a side effect. It is useful but should be used rarely. The more you have a better pattern such as MVP, MVVM and dependency injection, the less chance you need to use Mockito. spy .

Do nothing when a method is called Mockito?

Mockito 's doNothing() is used when you want to test void methods because void methods do not return anything so there is no way you can verify using assert. These void methods may be anywhere, for example, in service class, in dao class, etc.


2 Answers

From what I read on "Issue 53" of mockito (https://code.google.com/p/mockito/issues/detail?id=53) , my code was experiencing a problem due to the validation framework involved in Mockito. Precisely the following code was causing the exception per se.

private ConstantNode getConstantNode(NumericalValue value){     ConstantNode node = Mockito.mock(ConstantNode.class);     Mockito.when(node.evaluate()).thenReturn(value);     Mockito.when(node.toString()).thenReturn(value.toString());     return node; } 

If you remember from my code, the parameter value is ALSO A MOCK, so that when value.toString() is called on the thenReturn(), I believe (and someone please correct me if I am wrong) that the validation framework is triggered and makes sure that every "when" has had its thenReturn() called/validated/etc. So that if this happenes, the Mockito.when(node.toString()).thenReturn(value.toString() will not be validated because it hasn´t returned from the valute.toString(), which started the whole "validate everything" chain.

How I fixed it:

private ConstantNode getConstantNode(NumericalValue value){     ConstantNode node = Mockito.mock(ConstantNode.class);     Mockito.when(node.evaluate()).thenReturn(value);      String numberToString = value.toString();      Mockito.when(node.toString()).thenReturn(numberToString);     return node; } 

This way, it can be validated. I find this a complete code smell because I will literally have to leave a comment that explains why I am using a seemingly useless intermediate variable in the code.

Thanks for the help.

like image 169
Chayemor Avatar answered Sep 21 '22 23:09

Chayemor


There are some good fixes posted in this question already, but for anyone still having trouble understanding it, think of the order in which Java calls all those methods. According to the Java Language Specification, Java evaluates every parameter of a method left-to-right before calling the method:

  1. integerValue.getValue(), which Mockito records
  2. when, where Mockito takes the last call (to integer.getValue) and starts setting up stubbing
  3. value.toString, which is a mocked call that Mockito records
  4. thenReturn on the stubber

Mockito complains exactly because the call to the mock, step 3, happens after step 2 (when) but before step 4 (thenReturn), causing the validation framework to complain about the stubbing. Joy, your answer moves the troublesome step 3 to before step 1, which is fine; Sajan removes it from the statement entirely, which is also fine.

like image 28
Jeff Bowman Avatar answered Sep 25 '22 23:09

Jeff Bowman