Is there any way, using Mockito, to mock some methods in a class, but not others?
For example, in this (admittedly contrived) Stock
class I want to mock the getPrice()
and getQuantity()
return values (as shown in the test snippet below) but I want the getValue()
to perform the multiplication as coded in the Stock
class
public class Stock {
private final double price;
private final int quantity;
Stock(double price, int quantity) {
this.price = price;
this.quantity = quantity;
}
public double getPrice() {
return price;
}
public int getQuantity() {
return quantity;
}
public double getValue() {
return getPrice() * getQuantity();
}
@Test
public void getValueTest() {
Stock stock = mock(Stock.class);
when(stock.getPrice()).thenReturn(100.00);
when(stock.getQuantity()).thenReturn(200);
double value = stock.getValue();
// Unfortunately the following assert fails, because the mock Stock getValue() method does not perform the Stock.getValue() calculation code.
assertEquals("Stock value not correct", 100.00*200, value, .00001);
}
To directly answer your question, yes, you can mock some methods without mocking others. This is called a partial mock. See the Mockito documentation on partial mocks for more information.
For your example, you can do something like the following, in your test:
Stock stock = mock(Stock.class);
when(stock.getPrice()).thenReturn(100.00); // Mock implementation
when(stock.getQuantity()).thenReturn(200); // Mock implementation
when(stock.getValue()).thenCallRealMethod(); // Real implementation
In that case, each method implementation is mocked, unless specify thenCallRealMethod()
in the when(..)
clause.
There is also a possibility the other way around with spy instead of mock:
Stock stock = spy(Stock.class);
when(stock.getPrice()).thenReturn(100.00); // Mock implementation
when(stock.getQuantity()).thenReturn(200); // Mock implementation
// All other method call will use the real implementations
In that case, all method implementation are the real one, except if you have defined a mocked behaviour with when(..)
.
There is one important pitfall when you use when(Object)
with spy like in the previous example. The real method will be called (because stock.getPrice()
is evaluated before when(..)
at runtime). This can be a problem if your method contains logic that should not be called. You can write the previous example like this:
Stock stock = spy(Stock.class);
doReturn(100.00).when(stock).getPrice(); // Mock implementation
doReturn(200).when(stock).getQuantity(); // Mock implementation
// All other method call will use the real implementations
Another possibility may be to use org.mockito.Mockito.CALLS_REAL_METHODS
, such as:
Stock MOCK_STOCK = Mockito.mock( Stock.class, CALLS_REAL_METHODS );
This delegates unstubbed calls to real implementations.
However, with your example, I believe it will still fail, since the implementation of getValue()
relies on quantity
and price
, rather than getQuantity()
and getPrice()
, which is what you've mocked.
Another possibility is to avoid mocks altogether:
@Test
public void getValueTest() {
Stock stock = new Stock(100.00, 200);
double value = stock.getValue();
assertEquals("Stock value not correct", 100.00*200, value, .00001);
}
Partial mocking of a class is also supported via Spy in mockito
List list = new LinkedList();
List spy = spy(list);
//optionally, you can stub out some methods:
when(spy.size()).thenReturn(100);
//using the spy calls real methods
spy.add("one");
spy.add("two");
//size() method was stubbed - 100 is printed
System.out.println(spy.size());
Check the 1.10.19
and 2.7.22
docs for detailed explanation.
According to docs :
Foo mock = mock(Foo.class, CALLS_REAL_METHODS);
// this calls the real implementation of Foo.getSomething()
value = mock.getSomething();
when(mock.getSomething()).thenReturn(fakeValue);
// now fakeValue is returned
value = mock.getSomething();
class NaughtyLinkedList extends LinkedList { public int size() { throw new RuntimeException("don't call me");} } @Test public void partialMockNaughtLinkedList(){ List mock = mock(NaughtyLinkedList.class, CALLS_REAL_METHODS); mock.add(new Object()); // this calls the real function when(mock.size()).thenReturn(2); // For whatever reason, this lines throws the RuntimeException. assertEquals(2,mock.size()); }
This doesn't work. For whatever the reason, when "when" is executed, it actually executes the method that's supposed to be mocked. Code:
when(mock.getSomething()).thenReturn(fakeValue);
does not work, rather had to use doReturn(fakeValue).when(mock).getSomething()
What you want is org.mockito.Mockito.CALLS_REAL_METHODS
according to the docs:
/**
* Optional <code>Answer</code> to be used with {@link Mockito#mock(Class, Answer)}
* <p>
* {@link Answer} can be used to define the return values of unstubbed invocations.
* <p>
* This implementation can be helpful when working with legacy code.
* When this implementation is used, unstubbed methods will delegate to the real implementation.
* This is a way to create a partial mock object that calls real methods by default.
* <p>
* As usual you are going to read <b>the partial mock warning</b>:
* Object oriented programming is more less tackling complexity by dividing the complexity into separate, specific, SRPy objects.
* How does partial mock fit into this paradigm? Well, it just doesn't...
* Partial mock usually means that the complexity has been moved to a different method on the same object.
* In most cases, this is not the way you want to design your application.
* <p>
* However, there are rare cases when partial mocks come handy:
* dealing with code you cannot change easily (3rd party interfaces, interim refactoring of legacy code etc.)
* However, I wouldn't use partial mocks for new, test-driven & well-designed code.
* <p>
* Example:
* <pre class="code"><code class="java">
* Foo mock = mock(Foo.class, CALLS_REAL_METHODS);
*
* // this calls the real implementation of Foo.getSomething()
* value = mock.getSomething();
*
* when(mock.getSomething()).thenReturn(fakeValue);
*
* // now fakeValue is returned
* value = mock.getSomething();
* </code></pre>
*/
Thus your code should look like:
import org.junit.Test;
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
public class StockTest {
public class Stock {
private final double price;
private final int quantity;
Stock(double price, int quantity) {
this.price = price;
this.quantity = quantity;
}
public double getPrice() {
return price;
}
public int getQuantity() {
return quantity;
}
public double getValue() {
return getPrice() * getQuantity();
}
}
@Test
public void getValueTest() {
Stock stock = mock(Stock.class, withSettings().defaultAnswer(CALLS_REAL_METHODS));
when(stock.getPrice()).thenReturn(100.00);
when(stock.getQuantity()).thenReturn(200);
double value = stock.getValue();
assertEquals("Stock value not correct", 100.00 * 200, value, .00001);
}
}
The call to Stock stock = mock(Stock.class);
calls org.mockito.Mockito.mock(Class<T>)
which looks like this:
public static <T> T mock(Class<T> classToMock) {
return mock(classToMock, withSettings().defaultAnswer(RETURNS_DEFAULTS));
}
The docs of the value RETURNS_DEFAULTS
tell:
/**
* The default <code>Answer</code> of every mock <b>if</b> the mock was not stubbed.
* Typically it just returns some empty value.
* <p>
* {@link Answer} can be used to define the return values of unstubbed invocations.
* <p>
* This implementation first tries the global configuration.
* If there is no global configuration then it uses {@link ReturnsEmptyValues} (returns zeros, empty collections, nulls, etc.)
*/
withSettings()...
like that? It appears that org.mockito.internal.stubbing.answers.CallsRealMethods()
(for example) might do the job... and the javadoc for this class specifically says it's for use for partial mocks...
thenReturn
will actually execute the method (which might cause problems, although not in this example), and so doReturn
is preferable in such a case...?
Partial mocking using Mockito's spy method could be the solution to your problem, as already stated in the answers above. To some degree I agree that, for your concrete use case, it may be more appropriate to mock the DB lookup. From my experience this is not always possible - at least not without other workarounds - that I would consider as being very cumbersome or at least fragile. Note, that partial mocking does not work with ally versions of Mockito. You have use at least 1.8.0.
I would have just written a simple comment for the original question instead of posting this answer, but StackOverflow does not allow this.
Just one more thing: I really cannot understand that many times a question is being asked here gets comment with "Why you want to do this" without at least trying to understand the problem. Escpecially when it comes to then need for partial mocking there are really a lot of use cases that I could imagine where it would be useful. That's why the guys from Mockito provided that functionality. This feature should of course not be overused. But when we talk about test case setups that otherwise could not be established in a very complicated way, spying should be used.
Success story sharing
public static <T> T spy(java.lang.Class<T> classToSpy)
still has the annotation@Incubating
as I write in September 2016... if you really want to use partial mocking thespy
method should be called on an instanceStock stock = spy(Stock.class);
This seems wrong,spy
method seems to accept only objects not classes.doReturn(retval).when(spyObj).methodName(args)
andwhen(spyObj.methodName(args)).thenReturn(retval)