Mockito を使用して、クラス内の一部のメソッドをモックし、他のメソッドはモックしない方法はありますか?
たとえば、この(明らかに不自然な)Stock
クラスでは、をモックしgetPrice()
てgetQuantity()
値を返します(以下のテストスニペットに示すように)が、クラスgetValue()
でコード化された乗算を実行したいのです。Stock
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);
}
ベストアンサー1
質問に直接答えると、はい、他のメソッドをモックせずに一部のメソッドをモックすることができます。これは部分モックと呼ばれます。部分モックに関するMockitoのドキュメント詳細については。
たとえば、テストでは次のようなことができます。
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
その場合、句thenCallRealMethod()
で指定しない限り、各メソッドの実装はモック化されますwhen(..)
。
mockの代わりにspyを使うという逆のことも可能です。
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
その場合、 でモック動作を定義した場合を除き、すべてのメソッド実装は実際のものになりますwhen(..)
。
前の例のように spy を使用する場合、重要な落とし穴が 1 つありますwhen(Object)
。実際のメソッドが呼び出されます (実行時stock.getPrice()
に評価されるためwhen(..)
)。メソッドに呼び出されるべきではないロジックが含まれている場合、これが問題になることがあります。前の例は次のように記述できます。
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
別の方法org.mockito.Mockito.CALLS_REAL_METHODS
としては、次のように を使用することです。
Stock MOCK_STOCK = Mockito.mock( Stock.class, CALLS_REAL_METHODS );
これにより、スタブ化されていない呼び出しが実際の実装に委任されます。
ただし、あなたの例では、 の実装が、あなたがモックした および ではなく および に依存しているため、それでも失敗すると思いますgetValue()
。quantity
price
getQuantity()
getPrice()
もう一つの可能性は、モックを完全に回避することです。
@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);
}