如果添加了模块,则在单元测试中播放2.4依赖注入会忘记内置类

时间:2017-11-16 12:45:48

标签: java unit-testing playframework

我们正在将仅限Java的Play应用程序从Play 2.4迁移到Play 2.5。第一步:摆脱GlobalSettings,仍然完全在2.4领域。我写了一些StartModule,它将接管迁移指南和“互联网”描述的功能。我添加

play.modules.enabled += "de.[...].modules.StartModule"

到应用程序的.conf文件。通过sbt runsbt start执行此操作可按预期工作。但是,当我尝试使用sbt testsbt test-only对这些内容进行单元测试时会出现大量问题。

我们有一个相当精细的单元测试设置,因为应用程序很复杂并且具有大量的遗留部件。最终,Play服务器的单元测试实例以

启动
Helpers.start(testserver=Helpers.testServer(playhttpport,
    app=new GuiceApplicationBuilder()
      .configure(getConfiguration())
      .build()));

只要上面的play.modules.enabled行对单元测试代码不可见,此方法就可以正常工作。一旦启用它,我就会收到一些错误,比如

Test de.[...]Tests failed: com.google.inject.CreationException:
   Unable to create injector, see the following errors:

1) No implementation for play.inject.ApplicationLifecycle was bound.
   while locating play.inject.ApplicationLifecycle

2) Could not find a suitable constructor in play.api.Environment.
   Classes must have either one (and only one) constructor annotated with @Inject
   or a zero-argument constructor that is not private.

如果删除play.modules.enabled行并将服务器启动更改为

,则会发生同样的事情
Helpers.start(testserver=Helpers.testServer(playhttpport,
  app=new GuiceApplicationBuilder()
    .load(Guiceable.modules(new StartModule()))
    .configure(getConfiguration())
    .build()));

在我有限的理解中,如果给出了任何其他依赖关系定义,似乎GuiceApplicationBuilder(或其他)“忘记”所有内置依赖项注入配置。不幸的是,我没有在这里或其他任何地方发现任何可以引导我找到解决方案的适用帖子。

问题:

  1. 我的分析是否正确?
  2. 如何使用DI框架中的附加模块使我的单元测试代码正常运行?
  3. 在Play 2.5中直接继续会有帮助吗?我之前想解决这个问题,因为迁移步骤会带来很多东西需要处理,我真的要有一个功能基础 - 包括一个操作单元测试框架......
  4. 任何见解和帮助都非常感谢! 亲切的问候, 德克

    更新这是StartModule

    public class StartModule extends AbstractModule {
      @Override protected void configure() {
        bind(InnerServerLauncher.class).asEagerSingleton();
      }
    }
    

    这是InnerServerLauncher

    @Singleton
    public class InnerServerLauncher {
      @Inject
      public InnerServerLauncher(ApplicationLifecycle lifecycle,
                                 Environment environment) {
        System.err.println("*** Server launcher called ***");
      }
    }
    

    我应该补充一点,如果我把一个完全不同的类放到play.modules.enabled中,那么问题就出现了

    play.modules.enabled += "play.filters.cors.CORSModule"
    

1 个答案:

答案 0 :(得分:0)

好的,我终于明白了。问题是我在上面提到的GuiceBuilder.configure()方法,但没有进一步详述。正如我所说,我们的系统中有很多遗产。因此,我们有一种机制,可以独立于Play的配置文件构建配置,以进行单元测试。 fakeApplication()(以及基于play.modules.enabled的方法)将其与Play内部配置合并,但仅限于最顶层。对于普通设置(字符串,数字等),这是正常的,但对于值列表,这意味着完整列表被覆盖并替换

Play内部使用

application.conf来收集必须在依赖注入框架中注册的默认模块。文档非常清楚地表明您在play.modules.enabled中的陈述只能向play.modules.enabled += "package.Module" 添加元素,即

play.modules.enabled

我们为单元测试构建配置环境的“特殊方式”,但是,只要设置了我们自己的配置中的任何值,覆盖播放自己的GuiceApplicationBuilder。这破坏了Play的完整依赖注入方案,因为它自己的基类都不再可访问。无赖!

我通过实际使用“真实”配置文件解决了这个问题,该文件只是play.modules.enabled += ...正常读取并且包含那些GuiceApplicationBuilder行。由于此配置文件仍然是为单元测试场景人为地临时生成的,因此我通过System.setProperty将其名称传递给System.setProperty("config.file",conffilename); Helpers.start(testserver=Helpers.testServer(playhttpport, app=new GuiceApplicationBuilder().build()));

play.modules.enabled

现在,正确创建配置并使用 GlobalSettings的内部默认设置。现在,我终于可以开始实际将代码从{{1}}移动到注入且急切加载的模块中。这只是十个小时的狩猎......