单元测试JSR-330注入的对象

时间:2022-09-25 10:58:49

I have previously used Spring DI, and one of the benefits I perceive is that I can test my Spring bean classes without involving Spring (imports omitted for brevity):

我以前使用过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());
    }
}

Now I am experimenting with JSR-330, which means not explicitly writing setters.

现在我正在尝试使用JSR-330,这意味着没有明确地编写setter。

I'm using Hk2 so far, purely because of some anecdotal stuff about Jersey being tied to Hk2, and making it difficult to co-habit with other JSR-330 implementations.

到目前为止,我正在使用Hk2,纯粹是因为有些关于Jersey与Hk2绑定的传闻,并且难以与其他JSR-330实现共存。

public class Foo {
   @Inject 
   private String field;
}

I half expected some magic to happen, whereby the @Inject annotation caused a setter to become available, but this is not the case:

我有一半期望发生一些魔法,因此@Inject注释导致一个setter变得可用,但事实并非如此:

Foo foo = new Foo();
foo.setField("Bar"); // method setField(String) is undefined for the type Foo
  • How can I (conveniently) test this kind of annotated class without invoking a framework?
  • 如何在不调用框架的情况下(方便地)测试这种带注释的类?
  • Failing that, how can I invoke a framework in a portable way (i.e. without tightly coupling my test code to Hk2, Guice, etc.)
  • 如果做不到这一点,我怎么能以便携方式调用框架(即没有将我的测试代码紧密耦合到Hk2,Guice等)
  • Failing that, what's a typical, clean way to test classes annotated in this way?
  • 如果做不到这一点,以这种方式测试类的典型,干净的方法是什么?

4 个解决方案

#1


2  

Simplest is to make the fields package-private (instead of private), then in the test, set them directly. (That works if the test is in the same package)

最简单的方法是使字段package-private(而不是private),然后在测试中直接设置它们。 (如果测试在同一个包中,则有效)

public class Foo {
   @Inject 
   String field;
}



Foo foo = new Foo();
foo.field = "bar";

This has the advantage of avoiding reflection so it's safe for refactoring.

这具有避免反射的优点,因此可以安全地进行重构。

#2


1  

The field injection approach you mentioned is actually the typical Spring style; many programmers don't write setters for private injected fields at all. Spring (with @Autowired or @Inject) and JSR-330 containers usually inject fields using direct field reflection rather than setters.

你提到的现场注入方法实际上是典型的Spring风格;许多程序员根本没有为私有注入字段编写setter。 Spring(使用@Autowired或@Inject)和JSR-330容器通常使用直接场反射而不是setter来注入字段。

Because of this, if you don't want to use any DI framework, you could write the necessary reflection code into your unit tests yourself, but this seems like overkill just to avoid a test dependency; after all, the point of using @Inject is that you're coding to an interface, and you don't avoid using the JVM to avoid coupling to it.

因此,如果你不想使用任何DI框架,你可以自己在单元测试中编写必要的反射代码,但这似乎有点过分以避免测试依赖;毕竟,使用@Inject的关键在于您正在编写接口,并且不要避免使用JVM来避免与它耦合。

The usual approach for testing this sort of class is to set up a test context for whatever container you prefer and run the unit tests in that context. If you're using Spring, you'd put an applicationContext-test.xml file or TestConfig class in your src/test/ directory (or equivalent), and if you're using Guice, you'd write a module to wire up mocks or test datasets.

测试此类类的常用方法是为您喜欢的任何容器设置测试上下文,并在该上下文中运行单元测试。如果您正在使用Spring,那么您需要在src / test /目录(或等效的)中放置applicationContext-test.xml文件或TestConfig类,如果您使用的是Guice,则需要编写一个模块来连接模拟或测试数据集。

#3


1  

It turns out that frameworks relying on private/protected field access are not so uncommon. Hibernate, JPA, several JSR-330 implementations, including Spring itself, all do it.

事实证明,依赖私有/受保护的字段访问的框架并不是那么罕见。 Hibernate,JPA,几个JSR-330实现,包括Spring本身,都做到了。

Spring's spring-test package provides a ReflectionTestUtils class containing static methods for accessing these fields.

Spring的spring-test包提供了一个ReflectionTestUtils类,其中包含用于访问这些字段的静态方法。

Using this one can test the class in the question thus:

使用这个可以测试问题中的类:

import static org.springframework.test.util.ReflectionTestUtils.*;

...

@Test
public void testUsingSpringReflectionTestUtils() {
    Foo foo = new Foo();
    setField(foo, "field", "Bar");
    assertEquals("Bar", foo.getField());
}

You need spring-test and spring-core in your test classpath for this to work, but it doesn't add a dependency on Spring for your production code.

您需要在测试类路径中使用spring-test和spring-core才能使用它,但它不会为您的生产代码添加Spring依赖性。

(Comments welcome about alternative implementations of the same principle welcome. I don't think it's worth rolling one's own, however simple it would be, given that Spring has a good implementation.)

(评论欢迎关于相同原则欢迎的替代实现。我认为不值得推出自己的,不管它是多么简单,因为Spring有一个很好的实现。)

#4


1  

Give "needle" a try: http://needle.spree.de/overview

试试“针”:http://needle.spree.de/overview

needle is an DI-test-framework that only simulates the container behavior, making unit tests real simple.

needle是一个DI测试框架,只模拟容器行为,使单元测试变得非常简单。

#1


2  

Simplest is to make the fields package-private (instead of private), then in the test, set them directly. (That works if the test is in the same package)

最简单的方法是使字段package-private(而不是private),然后在测试中直接设置它们。 (如果测试在同一个包中,则有效)

public class Foo {
   @Inject 
   String field;
}



Foo foo = new Foo();
foo.field = "bar";

This has the advantage of avoiding reflection so it's safe for refactoring.

这具有避免反射的优点,因此可以安全地进行重构。

#2


1  

The field injection approach you mentioned is actually the typical Spring style; many programmers don't write setters for private injected fields at all. Spring (with @Autowired or @Inject) and JSR-330 containers usually inject fields using direct field reflection rather than setters.

你提到的现场注入方法实际上是典型的Spring风格;许多程序员根本没有为私有注入字段编写setter。 Spring(使用@Autowired或@Inject)和JSR-330容器通常使用直接场反射而不是setter来注入字段。

Because of this, if you don't want to use any DI framework, you could write the necessary reflection code into your unit tests yourself, but this seems like overkill just to avoid a test dependency; after all, the point of using @Inject is that you're coding to an interface, and you don't avoid using the JVM to avoid coupling to it.

因此,如果你不想使用任何DI框架,你可以自己在单元测试中编写必要的反射代码,但这似乎有点过分以避免测试依赖;毕竟,使用@Inject的关键在于您正在编写接口,并且不要避免使用JVM来避免与它耦合。

The usual approach for testing this sort of class is to set up a test context for whatever container you prefer and run the unit tests in that context. If you're using Spring, you'd put an applicationContext-test.xml file or TestConfig class in your src/test/ directory (or equivalent), and if you're using Guice, you'd write a module to wire up mocks or test datasets.

测试此类类的常用方法是为您喜欢的任何容器设置测试上下文,并在该上下文中运行单元测试。如果您正在使用Spring,那么您需要在src / test /目录(或等效的)中放置applicationContext-test.xml文件或TestConfig类,如果您使用的是Guice,则需要编写一个模块来连接模拟或测试数据集。

#3


1  

It turns out that frameworks relying on private/protected field access are not so uncommon. Hibernate, JPA, several JSR-330 implementations, including Spring itself, all do it.

事实证明,依赖私有/受保护的字段访问的框架并不是那么罕见。 Hibernate,JPA,几个JSR-330实现,包括Spring本身,都做到了。

Spring's spring-test package provides a ReflectionTestUtils class containing static methods for accessing these fields.

Spring的spring-test包提供了一个ReflectionTestUtils类,其中包含用于访问这些字段的静态方法。

Using this one can test the class in the question thus:

使用这个可以测试问题中的类:

import static org.springframework.test.util.ReflectionTestUtils.*;

...

@Test
public void testUsingSpringReflectionTestUtils() {
    Foo foo = new Foo();
    setField(foo, "field", "Bar");
    assertEquals("Bar", foo.getField());
}

You need spring-test and spring-core in your test classpath for this to work, but it doesn't add a dependency on Spring for your production code.

您需要在测试类路径中使用spring-test和spring-core才能使用它,但它不会为您的生产代码添加Spring依赖性。

(Comments welcome about alternative implementations of the same principle welcome. I don't think it's worth rolling one's own, however simple it would be, given that Spring has a good implementation.)

(评论欢迎关于相同原则欢迎的替代实现。我认为不值得推出自己的,不管它是多么简单,因为Spring有一个很好的实现。)

#4


1  

Give "needle" a try: http://needle.spree.de/overview

试试“针”:http://needle.spree.de/overview

needle is an DI-test-framework that only simulates the container behavior, making unit tests real simple.

needle是一个DI测试框架,只模拟容器行为,使单元测试变得非常简单。

相关文章