JUnit测试中的Guice注入器

Ale*_*noy 19 java junit guice code-injection

使用Guice,在每个JUnit测试类中获取一个新的注入器是一个好习惯,因为每个测试类应该是独立的吗?

Mic*_*mlk 36

你应该避免在单元测试中使用Guice,因为每个测试应该足够小,以至于手动DI是可管理的.通过在单元测试中使用Guice(或任何DI),您隐藏了一个警告,表明您的班级正在变得越来越重,承担了太多的责任.

为了测试引导程序代码和集成测试,然后是为每个测试创建一个不同的注入器.

  • 我从不直接注入没有二传手的场地.我几乎从不使用二传手注射.我发现这两个都是丑陋的并且隐藏了所述类的用户的类要求.我尝试只使用ctor注射.通过在单元测试中使用Guice(或任何DI),您隐藏了一个警告,表明您的班级正在变得越来越重,承担了太多的责任. (5认同)
  • 什么时候使用JUnit框架来运行集成测试? (5认同)
  • 我不同意.使用Guice,您可以使用@Inject并注入没有setter或构造函数的字段.它更具可读性.那么这种情况下的手动依赖应该是什么?我更喜欢使用Injector而不是手动Reflection API,因为它首先考虑到我. (4认同)
  • 您是否倾向于编写"浅层"单元测试来模拟测试主体的直接依赖性?我发现如果用真实存储等编写"全栈"测试,手动创建依赖树的大部分内容可能很麻烦.不想讨论哪种测试方法更好. (3认同)
  • 没有"更好"的"这个用例更好". (3认同)
  • +1 ...在所有测试中使用 guice 注入后,我现在觉得有必要恢复此决定,因为测试使用 Guice.createInjector 会消耗大量时间:( (2认同)
  • +1 测试应该非常简单,您不必查看另一个模块来查看您的代码是如何配置的。我赞同“通过在单元测试中使用 Guice(或任何 DI [框架]),你隐藏了一个警告,即你的类变得越来越大并承担了太多的责任” (2认同)

Joe*_*ams 27

万一有人偶然发现这个问题,并希望看到如何从单元测试中获取Guice注释,请从下面的基类扩展测试并调用 injector.injectMembers(this);

public class TestBase {
    protected Injector injector = Guice.createInjector(new AbstractModule() {
        @Override
        protected void configure() {
            bind(HelloService.class);
        }
    });

    @Before
    public void setup () {
        injector.injectMembers(this);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你的测试可以得到一个注入HelloService这样的

public class HelloServiceTest extends TestBase {
    @Inject
    HelloService service;

    @Test
    public void testService() throws Exception {
       //Do testing here
    }
}
Run Code Online (Sandbox Code Playgroud)


Adi*_*ing 10

我认为使用DI会使单元测试代码更简单,我总是使用DI进行单元测试以及集成测试.

没有DI,一切都很难编码.要么使用Guice Inject or 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);
    }

}
Run Code Online (Sandbox Code Playgroud)


小智 6

这取决于所使用的 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()));
        }

    }
Run Code Online (Sandbox Code Playgroud)

然后每个测试使用 RequiresInjection 注解,它可以接受一组内部模块进行聚合,或者不使用默认值。

    @RequiresInjection
    public class Junit5InjectWithoutModuleTest {

        @Inject
        private TestEnvironment environment;

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

    }
Run Code Online (Sandbox Code Playgroud)

这是注释:

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

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

    }
Run Code Online (Sandbox Code Playgroud)

JUnit5 对我来说仍然是新手,所以我可能正在研究模板,但到目前为止,扩展似乎可以解决问题。

对于 JUnit4,我们使用类似的方法,不同之处在于注入发生在我们自定义测试运行器的 createTest 方法中,然后每个测试实现一个 RequiresInjection 接口,该接口具有“getModule”方法。

我可能也应该对 TestNG 大喊大叫,因为 Guice 支持是内置的。 使用就像这样简单:

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

        @Inject
        SomeObject someObject;    

    }
Run Code Online (Sandbox Code Playgroud)


Sot*_*jor 5

看看Guice Berry吧.

我现在不建议使用它(文档非常糟糕),但是看看他们的方法可以让你清楚地了解如何在jUnit中完成DI.