小编典典

使用 Mockito 来模拟某些方法,但不能模拟其他方法

all

有没有办法使用 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);
}

阅读 144

收藏
2022-03-11

共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(..)子句中指定。

也有可能使用 spy 而不是 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

在这种情况下,所有方法实现都是真实的,除非您使用when(..).

when(Object)当您像上一个示例一样使用
spy时,有一个重要的陷阱。将调用真正的方法(因为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()依赖于quantityand
price,而不是getQuantity()and 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);
}
2022-03-11