【问题标题】:Production code + Test module-info = Unpossible?生产代码 + 测试模块信息 = 不可能?
【发布时间】:2020-03-17 15:46:10
【问题描述】:

我有一个模拟类,其中包含我从模块提供的服务的简单实现。我正在使用 OpenJDK 11.03、gradle 5.2.1 和 IntelliJ 2019.2。

/main/code/myPackage/myService.java 我有:

package myPackage;
class myService {
   public abstract void someFunction();
}

在我的test/code/somePackage/myMockService 我有:

package myPackage;
// no import, they're in the same package.
class myMockService extends myService {
   @Override
   public void someFunction() { System.out.prinln("Hello World"); }
}

在我的main/code/module-info.java 我有:

module myModule {
    exports somePackage;
}

我在test/code/module-info.java 上尝试了几种变体,但均未成功。例如:

// "open module" lets anyone use reflection within (mostly JUnit 5 in my case)
import myPackage.myService;
import myPackage.myMockService;
open module myTestModule { 
    exports myPackage;
    provides myService with myMockService
}

上面的module-info.java 引发了关于“模块名称 myTestModule 与预期名称 myModule 不匹配”、“包 'myPackage' 不可见”(来自 myMockModule.java)的错误,解释了“包 myPackage 在模块 myModule 中声明但模块 myTestModule 没有读取它”

另一方面,使用以下module-info.java,我得到了不同批次的错误(代码下方)

import myPackage.myService;
import myPackage.myMockService;
open module myModule {
    provides myService with myMockService;
}

如果没有requires myModule;,我的测试代码中对主代码分支的每次引用都会给出“错误:找不到符号”。 requires myModule;,我得到一个“错误:涉及 myModule 的循环依赖”。

所以...我的测试不能在不同的模块中。而且它们不能是同一个模块! [删除一长串脏话]

  • 如何在测试代码中引入服务的模拟版本,而不是创建完全不同的模块/gradle 子项目?

  • 或者这只是一个不可能的情况,虽然您可以拥有一个单独的测试模块信息,但您不能用它做很多事情?

  • 或者有没有办法在运行时动态加载东西,这样我就不必把每一个小模拟服务放在任何模块信息、测试或其他地方?这样ServiceLoader.load() 就会找到它们。嗯...也许扩展 ServiceLoader 并将其用法包装在主代码中,以便在生产代码或测试代码中使用正确的...

【问题讨论】:

  • 我在src/main/java 中只有一个module-info.java 文件。如果(假设)它不会包含在您的构建中,为什么您的测试目录需要一个?
  • 它将在测试中使用。我们完全是模块化的,并且能够启动一个微不足道的模拟服务似乎并不是太简单......我正在尝试测试。
  • 有点跑题了,但这个问题向我揭示了这里的 java 着色代码不知道:模块、打开、导出、提供、使用和几乎肯定是“到”。
  • 您绝对可以为您的测试代码设置一个单独的module-info,但我相信它只适用于“黑盒测试”,因为不允许拆分包。你能创建一个minimal reproducible example 来演示问题,包括build.gradle 文件吗?
  • 嗯,我大部分想通了。见下文。

标签: java mocking junit5 openjdk-11


【解决方案1】:

a) 欢迎来到“模块化世界中的测试”!

TL;DR https://sormuras.github.io/blog/2018-09-11-testing-in-the-modular-world.html

拥有一个或多个专用测试模块很好。带着所有的花里胡哨,阅读module-info.java声明。这些测试模块是您的主要模块的第一个客户。只需确保您的构建工具在编译和运行测试模块之前打包所有主要模块。否则,您不会尽可能接近实际地测试您的主模块——其他人会将您的主模块作为 JAR 文件使用。你也应该这样。这也解决了服务和多版本 JAR 的所有问题。

现在有趣的部分:模块内测试,也称为白盒测试。或者如何测试驻留在非导出包中的类型或导出包中的包私有类型?要么使用知道如何在测试编译和/或测试运行时将测试模块修补到主模块(反之亦然)的构建。像 proBach.java (我维护),或者在您使用 Gradle 的情况下,请参阅此答案的 b)elow 部分。

b) Gradle 和 Java main, test, ... 模块还不是开箱即用的朋友

基于插件的最佳解决方案:https://github.com/java9-modularity/gradle-modules-plugin -- 支持 在测试运行时传递这些 java 命令行选项 module-info.test 配置文件(我发明的)。在这里,您基本上通过详细的命令行选项描述您的测试模块要求,尽管已经存在完美的 DSL:module-info-java ... 循环回 a) 和模块感知构建工具。

c) IntelliJ IDEA 和 Java test 模块正在......改进!

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-21
  • 2012-03-03
  • 1970-01-01
  • 2019-12-28
  • 1970-01-01
相关资源
最近更新 更多