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

2022-08-31 04:20:10

有没有办法使用Mockito来模拟类中的某些方法,而不是其他方法?

例如,在这个(公认是人为的)类中,我想模拟和返回值(如下面的测试片段所示),但我希望执行类中编码的乘法StockgetPrice()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(..)

还有一种可能性是用间谍而不是嘲笑来反过来:

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(..)

当您与间谍一起使用时,有一个重要的陷阱,如上一个示例所示。将调用 real 方法(因为在运行时之前已进行评估)。如果您的方法包含不应调用的逻辑,则这可能是一个问题。您可以像这样编写前面的示例: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 );

这会将未存根的调用委托给实际实现。


但是,以你的例子,我相信它仍然会失败,因为依赖于 和 而不是 and ,这就是你所嘲笑的。getValue()quantitypricegetQuantity()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);
}

答案 2

部分模拟类也通过模拟中的间谍支持

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());

有关详细说明,请查看 1.10.192.7.22 文档。


推荐