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); }
For Mockito, there is no direct support to mock private and static methods. In order to test private methods, you will need to refactor the code to change the access to protected (or package) and you will have to avoid static/final methods.
The Mockito framework provides a variety of methods such as mock(), verify(), when(), etc., used to test Java applications. Using these predefined methods makes testing very easy.
Mockito provides following methods that can be used to mock void methods. doAnswer() : We can use this to perform some operations when a mocked object method is called that is returning void. doThrow() : We can use doThrow() when we want to stub a void method that throws exception.
With Mockito, you create a mock, tell Mockito what to do when specific methods are called on it, and then use the mock instance in your test instead of the real thing. After the test, you can query the mock to see what specific methods were called or check the side effects in the form of changed state.
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.
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); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With