Play 2.4 中的 Guice、DI 和单元测试
Guice, DI, and Unit Tests in Play 2.4
所以我一直在尝试通过文档自行解决这个问题,但我一无所获。
我在创建存储库对象的服务 class 中设置了一些简单的 DI 绑定。简单的。但是,当我 运行 在测试模式下执行此操作时,@Inject 什么也不做,并且永远不会实例化存储库对象。
@Inject
TagRepository tagRepository;
所以在使用它的那一行,在测试模式下,我们当然会得到一个 NullPointerException
tagRepository.tagExistsByName(tag);
这像这样冒泡到我的测试中:
[error] Test services.TagsServiceTest.testAddNewTag failed: java.lang.NullPointerException: null, took 0.097 sec
[error] at services.TagService.tagExists(TagService.java:27)
[error] at services.TagService.addNewTag(TagService.java:18)
[error] at services.TagsServiceTest.testAddNewTag(TagsServiceTest.java:29)
我的问题是,如何配置我的应用程序以在测试模式下使用 Guice 注入器?我的控制器没有这个问题,因为实际上是在向它们发出请求,设置完整的应用程序。
我应该提到的一件事是,我正在使用提供商将我的应用程序提供给测试。我应该使用 Guice 应用程序构建器吗?如果是这样,那会去哪里?播放文档在这方面不是很有帮助。这是供应商
@Override
protected FakeApplication provideFakeApplication() {
return new FakeApplication(new java.io.File("."), Helpers.class.getClassLoader(), ImmutableMap.of("play.http.router", "router.Routes"), new ArrayList<String>(), null);
}
更新:
根据以下建议更新
在我的 BaseTest 中 class
@Override
protected Application provideApplication() {
return new GuiceApplicationBuilder().in(Mode.TEST).build();
}
然后在服务测试中class
@Before
public void beforeTest() {
Injector injector = new GuiceInjectorBuilder().bindings(bind(TagService.class).toInstance(new TagService())).injector();
tagService = injector.instanceOf(TagService.class);
}
但是,我仍然遇到空指针异常,因为没有注入 TagRepository。
答案:
我在想这个有点不对。如果您使用需要注入的对象设置注入器,然后从中创建一个实例,您将不会再得到 NullPointerExceptions
@Before
public void beforeTest() {
Injector injector = new GuiceInjectorBuilder().bindings(bind(TagRepository.class).toInstance(new TagRepository())).injector();
tagService = injector.instanceOf(TagService.class);
}
如果您要扩展 WithApplication
,您可以将 protected Application provideApplication()
覆盖为 return 使用 GuiceApplicationBuilder
.
构建的 Application
例如(基于this code)您可以创建您的应用程序、添加或覆盖绑定等,并设置模式。如果您将 class 抽象化,它将自动与所有子 classes 一起工作。
public abstract class AbstractFakeApplicationTest extends WithApplication
{
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractFakeApplicationTest.class);
@Override
protected Application provideApplication()
{
return new GuiceApplicationBuilder().in(Mode.TEST)
.build();
}
@Override
public void startPlay()
{
super.startPlay();
// mock or otherwise provide a context
Http.Context.current.set(new Http.Context(1L,
Mockito.mock(RequestHeader.class),
Mockito.mock(Http.Request.class),
Collections.<String, String>emptyMap(),
Collections.<String, String>emptyMap(),
Collections.<String, Object>emptyMap()));
}
public Http.Context context()
{
return Http.Context.current.get();
}
}
子 classes 然后只需扩展此 class 并正常测试 - 所有 DI 应该像您 运行 应用程序正常时那样发生。
你可以看到它的各种例子here
这给出了您需要做的事情的基本轮廓。希望 https://playframework.com/documentation/2.4.x/JavaTestingWithGuice 上的文档现在会更有意义。
所以我一直在尝试通过文档自行解决这个问题,但我一无所获。
我在创建存储库对象的服务 class 中设置了一些简单的 DI 绑定。简单的。但是,当我 运行 在测试模式下执行此操作时,@Inject 什么也不做,并且永远不会实例化存储库对象。
@Inject
TagRepository tagRepository;
所以在使用它的那一行,在测试模式下,我们当然会得到一个 NullPointerException
tagRepository.tagExistsByName(tag);
这像这样冒泡到我的测试中:
[error] Test services.TagsServiceTest.testAddNewTag failed: java.lang.NullPointerException: null, took 0.097 sec
[error] at services.TagService.tagExists(TagService.java:27)
[error] at services.TagService.addNewTag(TagService.java:18)
[error] at services.TagsServiceTest.testAddNewTag(TagsServiceTest.java:29)
我的问题是,如何配置我的应用程序以在测试模式下使用 Guice 注入器?我的控制器没有这个问题,因为实际上是在向它们发出请求,设置完整的应用程序。
我应该提到的一件事是,我正在使用提供商将我的应用程序提供给测试。我应该使用 Guice 应用程序构建器吗?如果是这样,那会去哪里?播放文档在这方面不是很有帮助。这是供应商
@Override
protected FakeApplication provideFakeApplication() {
return new FakeApplication(new java.io.File("."), Helpers.class.getClassLoader(), ImmutableMap.of("play.http.router", "router.Routes"), new ArrayList<String>(), null);
}
更新:
根据以下建议更新
在我的 BaseTest 中 class
@Override
protected Application provideApplication() {
return new GuiceApplicationBuilder().in(Mode.TEST).build();
}
然后在服务测试中class
@Before
public void beforeTest() {
Injector injector = new GuiceInjectorBuilder().bindings(bind(TagService.class).toInstance(new TagService())).injector();
tagService = injector.instanceOf(TagService.class);
}
但是,我仍然遇到空指针异常,因为没有注入 TagRepository。
答案:
我在想这个有点不对。如果您使用需要注入的对象设置注入器,然后从中创建一个实例,您将不会再得到 NullPointerExceptions
@Before
public void beforeTest() {
Injector injector = new GuiceInjectorBuilder().bindings(bind(TagRepository.class).toInstance(new TagRepository())).injector();
tagService = injector.instanceOf(TagService.class);
}
如果您要扩展 WithApplication
,您可以将 protected Application provideApplication()
覆盖为 return 使用 GuiceApplicationBuilder
.
Application
例如(基于this code)您可以创建您的应用程序、添加或覆盖绑定等,并设置模式。如果您将 class 抽象化,它将自动与所有子 classes 一起工作。
public abstract class AbstractFakeApplicationTest extends WithApplication
{
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractFakeApplicationTest.class);
@Override
protected Application provideApplication()
{
return new GuiceApplicationBuilder().in(Mode.TEST)
.build();
}
@Override
public void startPlay()
{
super.startPlay();
// mock or otherwise provide a context
Http.Context.current.set(new Http.Context(1L,
Mockito.mock(RequestHeader.class),
Mockito.mock(Http.Request.class),
Collections.<String, String>emptyMap(),
Collections.<String, String>emptyMap(),
Collections.<String, Object>emptyMap()));
}
public Http.Context context()
{
return Http.Context.current.get();
}
}
子 classes 然后只需扩展此 class 并正常测试 - 所有 DI 应该像您 运行 应用程序正常时那样发生。
你可以看到它的各种例子here
这给出了您需要做的事情的基本轮廓。希望 https://playframework.com/documentation/2.4.x/JavaTestingWithGuice 上的文档现在会更有意义。