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

推荐答案

要直接回答你的问题,是的,你可以模仿一些方法而不模仿其他方法.这叫做partial mock.更多信息请参见the Mockito documentation on partial mocks.

对于您的示例,您可以在测试中执行类似以下操作:

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

在这种情况下,每个方法实现都是模拟的,除非在when(..)子句中指定thenCallRealMethod().

另一种可能是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一起使用时,有一个重要的trap .真正的方法将被调用(因为在运行时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()的实现依赖于quantityprice,而不是你嘲笑的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);
}

Java相关问答推荐

使用hibiter中特定字段的where条款自定义映射

Java事件系统通用转换为有界通配符

Java中不同包中的类之间的配置共享

为什么我们不能实现两个接口,其中一个接口有相同的签名,其中一个接口有默认的实现在java?'

springboot start loge change

JVM会优化这个数学运算吗?

CompleteableFuture是否运行在不同的内核上?

如何解释Java中for-each循环中对Iterable的强制转换方法引用?

使用多个RemoteDatabase对象的一个线程

由于在生成器模式中使用泛型,lambda表达式中的返回类型错误

Spring Boot&;Docker:无法执行目标org.springframework.boot:spring-boot-maven-plugin:3.2.0:build-image

Spring Boot中的应用程序.properties文件中未使用的属性

如果List是一个抽象接口,那么Collectors.toList()如何处理流呢?

如何使用MapStrCut转换双向链接

从泛型枚举创建EnumMap

Java KeyListener不工作或被添加

如何在Spring Boot中为不同的部署环境管理多个.properties文件?

如何在单元测试中获得我的装饰Mapstruct映射器的实例?

读取ConcurrentHashMap中的可变对象

当我try 返回可选时,Mock无法正常工作