Java 单元测试JSR-330注入对象
我以前使用过SpringDI,我认为其中一个好处是我可以在不涉及Spring的情况下测试我的Springbean类(为简洁起见,省略了导入): 现在我正在试验JSR-330,这意味着不显式地编写setter 到目前为止,我一直在使用Hk2,纯粹是因为一些关于Jersey与Hk2绑定的趣闻轶事,使得它难以与其他JSR-330实现共同习惯Java 单元测试JSR-330注入对象,java,guice,jsr330,hk2,Java,Guice,Jsr330,Hk2,我以前使用过SpringDI,我认为其中一个好处是我可以在不涉及Spring的情况下测试我的Springbean类(为简洁起见,省略了导入): 现在我正在试验JSR-330,这意味着不显式地编写setter 到目前为止,我一直在使用Hk2,纯粹是因为一些关于Jersey与Hk2绑定的趣闻轶事,使得它难以与其他JSR-330实现共同习惯 public class Foo { @Inject private String field; } 我有点期待会发生一些神奇的事情,@Injec
public class Foo {
@Inject
private String field;
}
我有点期待会发生一些神奇的事情,@Inject注释使setter变得可用,但事实并非如此:
Foo foo = new Foo();
foo.setField("Bar"); // method setField(String) is undefined for the type Foo
- 我如何(方便地)在不调用框架的情况下测试这种带注释的类
- 如果做不到这一点,我如何以可移植的方式调用框架(即不将测试代码与Hk2、Guice等紧密耦合)
- 如果做不到这一点,测试以这种方式注释的类的典型、干净的方法是什么
@Autowired
或@Inject
)和JSR-330容器通常使用直接字段反射而不是setter来注入字段
因此,如果您不想使用任何DI框架,您可以自己在单元测试中编写必要的反射代码,但为了避免测试依赖性,这似乎有些过分;毕竟,使用@Inject
的意义在于,您正在对一个接口进行编码,并且您不能避免使用JVM来避免与它的耦合
测试此类类的常用方法是为您喜欢的任何容器设置测试上下文,并在该上下文中运行单元测试。如果您使用的是Spring,您应该在
src/test/
目录(或等效目录)中放置一个applicationContext test.xml
文件或TestConfig
类,如果您使用的是Guice,您可以编写一个模块来连接模拟或测试数据集。事实证明,依赖私有/受保护字段访问的框架并不少见。Hibernate、JPA和几个JSR-330实现,包括Spring本身,都能做到这一点
Spring的Spring测试包提供了一个包含用于访问这些字段的静态方法的类
使用此选项可以测试问题中的类,因此:
import static org.springframework.test.util.ReflectionTestUtils.*;
...
@Test
public void testUsingSpringReflectionTestUtils() {
Foo foo = new Foo();
setField(foo, "field", "Bar");
assertEquals("Bar", foo.getField());
}
您需要在测试类路径中使用SpringTest和SpringCore,这样才能工作,但它不会为您的生产代码添加对spring的依赖
(欢迎对同一原则的替代实现发表评论欢迎。我认为,考虑到Spring有一个很好的实现,不管它多么简单,都不值得自己动手。)尝试一下“针”:
needle是一个DI测试框架,它只模拟容器行为,使单元测试变得非常简单 最简单的方法是将字段包设为私有(而不是私有),然后在测试中直接设置它们。(如果测试在同一个包中,则该选项有效)
这样做的好处是避免了反射,因此可以安全地进行重构。可能的重复我认为这是有区别的。链接的问题是“我是否应该写二传”。这个问题是“如果我不使用setter,我应该如何测试”。只需使用构造函数注入。这个问题到时候就会解决了。
import static org.springframework.test.util.ReflectionTestUtils.*;
...
@Test
public void testUsingSpringReflectionTestUtils() {
Foo foo = new Foo();
setField(foo, "field", "Bar");
assertEquals("Bar", foo.getField());
}
public class Foo {
@Inject
String field;
}
Foo foo = new Foo();
foo.field = "bar";