生产代码 + 测试模块信息 = 不可能?

Mar*_*rer 8 java mocking junit5 openjdk-11

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

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

package myPackage;
class myService {
   public abstract void someFunction();
}
Run Code Online (Sandbox Code Playgroud)

在我的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"); }
}
Run Code Online (Sandbox Code Playgroud)

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

module myModule {
    exports somePackage;
}
Run Code Online (Sandbox Code Playgroud)

我在 a 上尝试了几种变体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
}
Run Code Online (Sandbox Code Playgroud)

上面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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

Sor*_*ras 12

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

TL;博士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——它尊重在测试运行时 module-info.test配置文件(我发明的)中传递这些 java 命令行选项。在这里,您基本上通过详细的命令行选项来描述您的测试模块要求,尽管完美的 DSL 已经存在:module-info-java...循环回到 a) 和模块感知构建工具。

c) IntelliJ IDEA 和 Java测试模块正在……改进!