Java JUnit测试中的Guice注入器

Java JUnit测试中的Guice注入器,java,junit,guice,code-injection,Java,Junit,Guice,Code Injection,使用Guice,在每个JUnit测试类中获得一个新的注入器是否是一个好的实践,因为每个测试类都应该是独立的?您应该真正避免在单元测试中使用Guice,因为每个测试都应该足够小,可以管理手动DI。通过在单元测试中使用Guice(或任何DI),您隐藏了一个警告,即您的类变得太大,承担了太多的责任 对于测试引导程序代码和集成测试,则是为每个测试创建一个不同的注入器。我认为使用DI将使单元测试代码更简单,我总是将DI用于单元测试和集成测试 没有DI,一切都很难编码。使用Guice-Inject或Spri

使用Guice,在每个JUnit测试类中获得一个新的注入器是否是一个好的实践,因为每个测试类都应该是独立的?

您应该真正避免在单元测试中使用Guice,因为每个测试都应该足够小,可以管理手动DI。通过在单元测试中使用Guice(或任何DI),您隐藏了一个警告,即您的类变得太大,承担了太多的责任


对于测试引导程序代码和集成测试,则是为每个测试创建一个不同的注入器。

我认为使用
DI
将使单元测试代码更简单,我总是将DI用于单元测试和集成测试

没有DI,一切都很难编码。使用
Guice-Inject或Spring-Autowired
。就像我下面的测试代码:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "/application-context.xml")
public class When_inexists_user_disabled {
    @Autowired
    IRegistrationService registrationService;

    private int userId;

    @Before
    public void setUp() {
        Logger.getRootLogger().setLevel(Level.INFO);
        Logger.getLogger("org.springframework").setLevel(Level.WARN);
        BasicConfigurator.configure();

        userId = 999;
    }

    @Test(expected=UserNotFoundException.class)
    public void user_should_have_disabled() throws UserNotFoundException {
        registrationService.disable(userId);
    }

}
看一看

我不建议现在就使用它(文档编写非常糟糕),但是查看他们的方法可以让您清楚地思考应该如何在jUnit中完成DI

我发现它是Guice的一个很好的补充(它甚至处理模拟框架集成)


这使得单元测试类非常清晰和简洁(在那里永远看不到
注入器),并且在适当的情况下,还允许您在单元测试中使用生产绑定。

我建议使用我最近编写的框架

这非常简单,通过两个注释,您可以在应用程序的相同上下文中运行测试


您可以在Guice模块中定义您的模拟,这样就很容易重用它们。

如果有人偶然发现这个问题,想看看如何从单元测试中获得Guice注释,请从下面的基类扩展您的测试,并调用
injector.injectMembers(this)

然后,您的测试可以得到如下注入的
HelloService

public class HelloServiceTest extends TestBase {
    @Inject
    HelloService service;

    @Test
    public void testService() throws Exception {
       //Do testing here
    }
}

这取决于正在使用哪个版本的JUnit。我们的团队已经成功地使用了Junit4,现在正在研究JUnit5

在Junit5中,我们使用扩展

    public class InjectionPoint implements BeforeTestExecutionCallback {

        @Override
        public void beforeTestExecution(ExtensionContext context) throws Exception {

            List<Module> modules = Lists.newArrayList(new ConfigurationModule());

            Optional<Object> test = context.getTestInstance();

            if (test.isPresent()) {
                RequiresInjection requiresInjection = test.get().getClass().getAnnotation(RequiresInjection.class);

                if (requiresInjection != null) {
                    for (Class c : requiresInjection.values()) {
                        modules.add((Module) c.newInstance());
                    }
                }

                Module aggregate = Modules.combine(modules);
                Injector injector = Guice.createInjector(aggregate);

                injector.injectMembers(test.get());
                getStore(context).put(injector.getClass(), injector);
            }

        }

        private Store getStore(ExtensionContext context) {
            return context.getStore(Namespace.create(getClass()));
        }

    }
下面是注释:

    @ExtendWith(InjectionPoint.class)
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
    public @interface RequiresInjection {

        Class<? extends Module>[] values() default {};

    }

就个人而言,我认为这很难解决,因为我需要查看应用程序上下文文件,以了解IRegistrationService正在使用的是什么,是否需要任何模拟或存根,以及它们是如何设置的。如果一个测试觉得手工编写代码太难,那么这表明您可能测试太多,或者您的对象可能需要太多才能开始。@mlk注释配置没有那么糟糕,因为您可以在一个[at]配置bean中设置您想要的一切,包括模拟,您可以将其作为一个内部类。我不同意。使用Guice,您可以使用@Inject和Inject字段,而不使用setter或构造函数。它更具可读性。那么手动依赖在这种情况下应该是什么呢?我更喜欢使用注入器而不是手动反射API,因为我首先想到的是注入器。我从不在没有设置器的情况下直接注入字段。我几乎从不使用塞特注射。我发现这两个类都很难看,并且对所述类的用户隐藏了类的需求。我试着只使用ctor注入。通过在单元测试中使用Guice(或任何DI),您隐藏了一个警告,即您的类正在变得越来越大,并且承担了太多的责任。您是否倾向于编写模拟测试主体直接依赖关系的“浅层”单元测试?我发现,如果您使用真实存储等编写“完整堆栈”测试,手动创建大部分依赖关系树可能会很麻烦。不过,我不想就哪种测试方法更好展开争论。没有“更好”的说法,只有“适合此用例”的说法。JUnit框架何时用于运行集成测试呢?如果我是对的,AtUnit source base的最后一次提交是在2008年。如果您决定使用GuiceBerry,您可以使
@提供同样具有
@TestScoped
注释()(或
绑定(YourClass.class).in(TestScoped.class);
)的
函数。这告诉Guice每个测试只创建一个实例,而@Singleton会使组件在测试中重用,或者没有注释,每次注入时都会创建一个新实例(每个测试可以有多个实例)。您应该注意
injectMembers
要测试并需要注入的类,不仅仅是
this
这是测试仪类。它应该是
HelloServiceTest
,而不是
HelloServletTest
和“helloserviceservice;”不
HelloServlet servlet?我假设是这样,并编辑了您的答案。
TestBase
应该是
abstract
    @RequiresInjection
    public class Junit5InjectWithoutModuleTest {

        @Inject
        private TestEnvironment environment;

        @Test
        public void shouldAccessFromOuterModule() {
            assertThat(environment).isNotNull();
        }

    }
    @ExtendWith(InjectionPoint.class)
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
    public @interface RequiresInjection {

        Class<? extends Module>[] values() default {};

    }
@Guice({SomeObjectModule.class})
    public class MyTest {

        @Inject
        SomeObject someObject;    

    }