Spring注释 - 好还是坏?

时间:2012-05-03 15:44:18

标签: java spring unit-testing spring-annotations

我最近喜欢这样的课程:

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()方法
  3. 在春季注释之前的几天,这个课程就像这样写了:

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

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

    那么,春季注释是好事还是倒退了?是否有时候我应该使用它们以及何时应该使用旧的XML应用程序上下文?

    谢谢, 喷枪。

4 个答案:

答案 0 :(得分: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;
    }

}

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

答案 1 :(得分:2)

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

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

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注释的问题,不正确使用它们是一个问题。

答案 2 :(得分:0)

您仍然可以在setter和构造函数上使用注释,我个人更喜欢这样,因为它使依赖更加明显。这50个参数构造函数确实很突出。

答案 3 :(得分:0)

虽然我同意axtavt的回答,但一个快速的解决方法是使用spring-test工件中的ReflectionTestUtils类。它为这种情况提供了很好的单行:

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

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

请参阅ReflectionTestUtils