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
然后每个测试使用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 extends Module>[] values() default {}; }
JUnit5对我来说仍然是新手,所以我可能正在研究模板,但到目前为止,Extensions似乎都在耍手段。
使用JUnit4,我们使用类似的方法,除了注入发生在我们的自定义测试运行器的createTest方法中,然后每个测试实现一个具有“getModule”方法的RequiresInjection接口。
我可能也应该向TestNG大吼一声,因为Guice支持就是内置的。用法就像这样简单:
@Guice({SomeObjectModule.class}) public class MyTest { @Inject SomeObject someObject; }