Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring注释-好还是坏?_Java_Spring_Unit Testing_Spring Annotations - Fatal编程技术网

Java Spring注释-好还是坏?

Java Spring注释-好还是坏?,java,spring,unit-testing,spring-annotations,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() { jdbcTemp

我最近遇到过这样一个班:

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);
   }

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

   public SomeDao(DataSource dataSource, String sql) {
      this.jdbcTemplate = new JdbcTemplate(dataSource);
      this.sql = sql;
   }    
   ...
}
现在,我想通过注入数据源和SQL字符串来对这个类进行单元测试。据我所知,有两种选择:

  • 加载一个很慢的应用程序上下文,很可能会加载很多我在测试中不需要的东西
  • 使用反射设置私有属性并调用private postConstruct()方法
  • 在spring注释之前的日子里,类的编写方式应该是这样的:

    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);
       }
    
       ...
    }
    
    public class SomeDao {
       private String sql;
       private JdbcTemplate jdbcTemplate;
    
       public SomeDao(DataSource dataSource, String sql) {
          this.jdbcTemplate = new JdbcTemplate(dataSource);
          this.sql = sql;
       }    
       ...
    }
    
    我可以很容易地测试这个类,而不需要反射或spring。我的类是纯pojo,没有spring依赖项

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

    谢谢,
    Lance.

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

    为什么不用模拟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;
        }
    
    }
    
    @配置
    公共类DataAccessConfiguration{
    @豆子
    公共数据源数据源(){
    DataSource DataSource=mock(DataSource.class);
    返回数据源;
    }
    @豆子
    公共地图someMap(){
    Map Map=newhashmap();
    map.put(“someDao.sql”、“somevalue”);
    返回图;
    }
    }
    

    因此,与其放弃自动布线,您实际上可以利用它。此外,您还将加载的上下文限制为被测试类所需的内容。

    我想说的是,与构造函数注入相比,存在一种不健康的倾向,即即使对于所需的依赖项,也更喜欢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注释的问题,而是错误使用它们的问题。

    虽然我同意axtavt的答案,但一个快速解决方法是使用Spring测试工件中的
    ReflectionTestUtils
    类。它为这样的场景提供了很好的一行程序:

    ReflectionTestUtils.setField(dao, "dataSource", mydataSource);
    
    对于单元测试,这是最简单的


    这绝对是太棒了,正是我想要的。谢谢soulcheck。我真的不喜欢这种方法,而且我觉得它很粗糙。我还需要反射地调用postConstruct()方法。再一次,哈奇。我知道,出于这个原因,我根本不喜欢私人注释字段。但这是解决这个问题的最简单方法。我不同意,soulcheck提供了一种使用@Configuration注入依赖项的极好方法。它比手动反射干净得多。@uklance它很好,当然也更干净,但我还是要说我的方法更简单。重构代码时反射不会重构。ReflectionTestUtils也不允许我调用私有方法。您能提供一些理由说明为什么您发现setter/field-inject“不健康”吗?在我看来,当你有一些简单的选择,比如Mockito或者soulcheck发布的解决方案时,为你已经列出的元素添加一个构造函数本质上是代码重复,因此,就是混乱。我很难想出一个不使用现场注射的好理由。它的生产速度一样快,书写速度更快,杂乱程度更低,更清晰。。。那么你为什么不喜欢它呢?@TimPote:我可以想出几个反对场注入的理由:没有反射或spring之类的框架就无法进行测试;不会使依赖关系显式化;创建上帝类太容易了;你很容易错过“太多依赖”的味道;字段不能是
    final
    ,即使它们应该是不可变的…