我以前使用过Spring DI,我认为其中一个好处就是我可以在不涉及Spring的情况下测试我的Spring bean类(为简洁起见省略了导入):
public class Foo {
private String field;
public void setField(String field) { this.field = field; }
public String getField() { return field; }
}
public class TestFoo {
@Test
public void test_field_is_set() {
Foo foo = new Foo();
foo.setField("Bar");
assertEquals("Bar", foo.getField());
}
}
现在我正在尝试使用JSR-330,这意味着没有明确地编写setter。
到目前为止,我正在使用Hk2,纯粹是因为有些关于Jersey与Hk2绑定的轶事,并且难以与其他JSR-330实现共存。
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
答案 0 :(得分:2)
最简单的方法是使字段包为私有(而不是私有),然后在测试中直接设置它们。 (如果测试在同一个包中,那就有效)
public class Foo {
@Inject
String field;
}
Foo foo = new Foo();
foo.field = "bar";
这具有避免反射的优点,因此可以安全地进行重构。
答案 1 :(得分:1)
你提到的现场注入方法实际上是典型的春季风格;许多程序员根本没有为私有注入字段编写setter。 Spring(带有@Autowired
或@Inject
)和JSR-330容器通常使用直接场反射而不是设置器来注入字段。
因此,如果您不想使用任何DI框架,您可以自己将必要的反射代码编写到单元测试中,但这似乎有点过分以避免测试依赖;毕竟,使用@Inject
的关键在于您正在编写接口,并且不要避免使用JVM来避免与它耦合。
测试此类类的常用方法是为您喜欢的任何容器设置测试上下文,并在该上下文中运行单元测试。如果您正在使用Spring,那么您需要在applicationContext-test.xml
目录(或等效文件)中放置TestConfig
文件或src/test/
类,如果您使用的是Guice,则需要编写用于连接模拟或测试数据集的模块。
答案 2 :(得分:1)
事实证明,依赖私有/受保护的字段访问的框架并不是那么罕见。 Hibernate,JPA,几个JSR-330实现,包括Spring本身,都是这样做的。
Spring的spring-test包提供了一个ReflectionTestUtils类,其中包含用于访问这些字段的静态方法。
使用这个可以测试问题中的类:
import static org.springframework.test.util.ReflectionTestUtils.*;
...
@Test
public void testUsingSpringReflectionTestUtils() {
Foo foo = new Foo();
setField(foo, "field", "Bar");
assertEquals("Bar", foo.getField());
}
您需要在测试类路径中使用spring-test和spring-core才能使用它,但它不会为您的生产代码添加对Spring的依赖。
(评论欢迎关于相同原则欢迎的替代实现。我认为不值得推出自己的,不管它是多么简单,因为Spring有一个很好的实现。)
答案 3 :(得分:1)
尝试“针”:http://needle.spree.de/overview
needle是一个DI测试框架,它只模拟容器行为,使单元测试变得非常简单。