【问题标题】:How to mock a class created in constructor?如何模拟在构造函数中创建的类?
【发布时间】:2019-08-07 10:57:01
【问题描述】:

想象一下,我有一个 bean JdbcTemplate,并且只有一次课程我需要明确的 NamedParameterJdbcTemplate。它是在构造函数内部创建的。

问题:如何在junit 测试期间模拟它?

@Service
public class QueryService {
    private final NamedParameterJdbcTemplate namedJdbc;

    public BookingExportService(JdbcTemplate jdbc) {
        this.namedJdbc = new NamedParameterJdbcTemplate(jdbc);
    }

    public void sql() {
        namedJdbc.query(sql1, mapSqlParameterSource, resultSetExtractor);
        namedJdbc.query(sql2, mapSqlParameterSource, resultSetExtractor);
    } 
}

在这里定义模拟很困难,因为我必须模拟底层的JdbcTemplate 调用。这可以按如下方式工作:

@MockBean
private JdbcTemplate jdbc;

@Test
public void testQuery() {
    when(jdbc.query(any(PreparedStatementCreator.class), any(ResultSetExtractor.class))).thenReturn(..);
}

但是:如果我有不同的 sql 查询应该产生不同的结果(如上面的 sql1 和 sql2),那么我很不走运,并且在模拟期间不能区分 sql。

我的机会有多大?

【问题讨论】:

  • 您不自动装配它是否有特定原因?您可以为您的模板添加一个(受保护的)setter
  • 嗯,我只需要该服务中的NamedParameterJdbcTemplate,其他地方都不需要。那么我将模板直接创建为@Bean 应用程序范围会更好吗?
  • 出于功能目的,您可能只需要它一次,但正如您所注意到的,您仍然必须能够设置一个 mock/... 以用于测试目的。仅仅因为您现在只需要它一次,并不意味着您以后不再需要它。现在,您有一个硬编码的实例化。如果您想使用其他构造函数,自动装配它还将确保您不必更改此类
  • Spring Boot 已经创建了一个开箱即用的NamedParameterJdbcTemplate。 S 你实际上是在你的代码中创建另一个。只需注入预配置的。
  • 我不知道这个,你!

标签: java spring spring-boot junit spring-jdbc


【解决方案1】:

这里:

this.namedJdbc = new NamedParameterJdbcTemplate(jdbc);

这只会让您的代码难以测试。基本上,您在这里绕过了依赖注入,这意味着:您无法控制该字段内容。

三个选项:

  • 转而使用 PowerMock(ito) 或 JMockit 等模拟框架,允许您控制对 new() 的调用(不推荐)
  • 更改您的代码,例如使用构造函数伸缩...以便您可以在该类的实例中简单地传递(然后可以轻松地使用 Mockito 等“普通”框架进行模拟)
  • 因为您已经在使用具有自己的依赖注入思想的框架(例如@Autowired):退后一步,执行框架暗示的事情。

【讨论】:

    猜你喜欢
    • 2013-07-10
    • 1970-01-01
    • 2016-01-02
    • 2019-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    • 2019-08-13
    相关资源
    最近更新 更多