JUnit中的Guice注入器测试

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

看看Guice Berry吧 。

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

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

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

如果有人偶然发现这个问题,并希望看到如何从unit testing中获取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); } } 

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

 public class HelloServiceTest extends TestBase { @Inject HelloService service; @Test public void testService() throws Exception { //Do testing here } } 

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

没有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); } } 

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

这使得unit testing类非常清晰简洁(从未在那里看到过Injector ),并且在适当的情况下,还允许您将生产绑定作为unit testing的一部分进行操作。

我建议我最近写的这个框架是Guice-Behave 。

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

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

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

在Junit5中,我们使用扩展。

  public class InjectionPoint implements BeforeTestExecutionCallback { @Override public void beforeTestExecution(ExtensionContext context) throws Exception { List modules = Lists.newArrayList(new ConfigurationModule()); Optional 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())); } } 

然后每个测试使用RequiresInjection批注,它可以接受要聚合的内部模块数组,或者不使用默认值。

  @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[] values() default {}; } 

JUnit5对我来说仍然是新手,所以我可能正在研究模板,但到目前为止,Extensions似乎都在耍手段。

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

我可能也应该向TestNG大吼一声,因为Guice支持就是内置的。用法就像这样简单:

 @Guice({SomeObjectModule.class}) public class MyTest { @Inject SomeObject someObject; }