0

我最近遇到了这样的课程:

public class SomeDao {
   @Inject
   private DataSource dataSource;

   @Value("#{someMap['someDao.sql']}")
   private String sql;

   private JdbcTemplate jdbcTemplate;

   @PostConstruct
   private void postConstruct() {
      jdbcTemplate = new JdbcTemplate(dataSource);
   }

   ...
}

现在我想通过注入 DataSource 和 SQL 字符串来对这个类进行单元测试。据我所知,有两种选择:

  1. 加载一个速度很慢的应用程序上下文,并且很可能会加载很多我不需要的测试内容
  2. 使用反射设置私有属性并调用私有 postConstruct() 方法

在 spring 注释之前的日子里,这个类应该是这样写的:

public class SomeDao {
   private String sql;
   private JdbcTemplate jdbcTemplate;

   public SomeDao(DataSource dataSource, String sql) {
      this.jdbcTemplate = new JdbcTemplate(dataSource);
      this.sql = sql;
   }    
   ...
}

而且我可以很容易地测试这个类,而不需要反射或弹簧。我的班级是一个纯粹的 pojo,没有 spring 依赖项。

那么,spring 注释是一件好事还是倒退了一步?是否有时我应该使用它们,有时我应该使用旧的 XML 应用程序上下文?

谢谢,兰斯。

4

4 回答 4

4

为什么不使用 bean 模拟声明一个测试上下文并从中注入您的班级所需的那些?这就是人们通常会做的事情,而且非常简单。

最轻量级的方法是在您的测试类中提供一个内部类,@Configuration并使用提供模拟的方法进行注释:

@Configuration
public class DataAccessConfiguration {

    @Bean
    public DataSource dataSource() {
        DataSource dataSource =  mock(Datasource.class);
        return dataSource;
    }

    @Bean
    public Map<String,String> someMap() {
        Map<String, String> map = new HashMap<>();
        map.put("someDao.sql", "somevalue");
        return map;
    }

}

因此,您实际上可以利用它,而不是放弃自动装配。此外,您将加载的上下文限制为被测类所需的内容。

于 2012-05-03T15:56:33.657 回答
3

我想说的是,private即使对于所需的依赖项,也有一种不健康的倾向,即更喜欢 setter 注入(甚至注入到字段中)而不是构造函数注入。

请注意,由于此示例中的两个依赖项都是必需的,因此可以将其重写如下:

public class SomeDao {
    private String sql;
    private JdbcTemplate jdbcTemplate;

    @Inject  
    public SomeDao(
        DataSource dataSource, 
        @Value("#{someMap['someDao.sql']}") String sql) {

        this.jdbcTemplate = new JdbcTemplate(dataSource);
        this.sql = sql;
    }   
    ...
}

所以,这不是 Spring 注解的问题,而是错误使用它们的问题。

于 2012-05-03T15:59:49.387 回答
0

您仍然可以在设置器和构造器上使用注释,我个人更喜欢它,因为它使依赖关系更加明显。那 50 个参数构造函数真的很突出。

于 2012-05-03T15:46:48.210 回答
0

虽然我同意 axtavt 的回答,但一个快速的解决方法是使用ReflectionTestUtilsspring-test 工件中的类。它为此类场景提供了很好的单行代码:

ReflectionTestUtils.setField(dao, "dataSource", mydataSource);

对于单元测试,这很简单。

ReflectionTestUtils

于 2012-05-03T16:11:15.583 回答