【问题标题】:Difference between a spy and a mock with delegation in MockitoMockito 中的间谍和带代表团的模拟之间的区别
【发布时间】:2020-03-02 13:26:56
【问题描述】:

我正在为一个从 Kafka 获取某些对象、验证它们、执行各种转换并将转换后的对象保存到另一个数据库或将错误响应发送回 Kafka 的应用程序编写集成测试。

生产数据库有几个命名查询,这些查询映射到相应 JpaRepository 中的相关方法,如下所示:

public interface PositionRepository extends JpaRepository<Position, Long> {

  @Procedure(name = "generatePositionCode")
  void generatePositionCode(@Param("clientCode") Integer clientCode);
//remainder omitted

我正在使用 Mockito 框架和 H2 内存数据库进行集成测试。由于测试数据库不包含此类命名查询,我想存根存储库中的相应方法,并且在调用它们时什么都不做(这对于测试目的是可以的),但继续调用存储库的其他非存根方法。

我一直认为这是你应该在 Mockito 中使用间谍的时候。但是,当我这样定义间谍时:

@Spy
private PositionRespository positionRepository;

public void setUp() {
    doNothing().when(positionRepository).generatePositionCode(anyInt());
}

我的集成测试失败,异常归结为:

原因:org.h2.jdbc.JdbcSQLException:找不到数据库“FT”; SQL 语句: 调用 FT.Ftposgn.generatePositionCode(?) [90013-197]

另一方面,如果我在配置类中定义一个带委托的模拟,如下所示:

@Primary
@Bean
public PositionRepository mockPositionRepository(PositionRepository positionRepository) {
    return Mockito.mock(PositionRepository.class, 
                        AdditionalAnswers.delegatesTo(positionRepository));
}

并在测试类中自动装配存储库:

@Autowired
private PositionRepository positionRepository;

public void setUp() {
    doNothing().when(positionRepository).generatePositionCode(anyInt());
}

所有测试都是绿色的。

我一直试图弄清楚为什么这两种方法会产生不同的结果但不能。任何人都可以解释一下吗?

谢谢。

【问题讨论】:

    标签: mocking mockito integration-testing spy


    【解决方案1】:

    我设法解决了这个问题。

    第一个问题是我使用 @Spy 注释而不是 @SpyBean 注释,因此 Spring 没有将间谍作为 bean 进行管理。

    下一个陷阱是 Spring Data JPA 将存储库的实现创建为具有最终方法的 CGLIB 代理,因此不能仅使用 Mockito 核心库创建 Spy。您必须在类路径中添加 org.mockito:mockito-inline 依赖项。

    最后的考虑是Mockito.verify() 和其他此类方法将失败并返回MockitoException,因为它们将在目标对象而不是 Spy 上调用。为了克服这个问题,创建一个间谍作为

    @SpyBean(proxyTargetAware = false)
    

    在这种情况下,对 verify() 的调用将直接使用代理而不是 AOP 建议 bean 的目标。

    【讨论】:

      【解决方案2】:

      在第一种情况下,您应该在PositionRepository 上使用@Spy 而不是PersonRepository。 如果您正在测试PositionRepository 并想模拟其类的方法,那么您应该在PositionRepository 上创建Spy。如果您正在测试 PositionRepository 并想模拟像 PersonRepository 这样的另一个类,那么您应该在 PersonRepository 上创建 Mock 换句话说:Spy 是部分嘲弄,Mock 是完全嘲弄。如果您对对象进行 Spy 并且不提供 when().thenReturn() 那么它将尝试使用现有的实现。

      【讨论】:

      • 这只是一个错字。我已经更正了这个问题。显然我说的是单个存储库。
      猜你喜欢
      • 2013-02-09
      • 2017-07-12
      • 2023-02-01
      • 2021-05-05
      • 1970-01-01
      • 2011-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多