不使用Maven或Gradle,如何在Java 9中使用JUnit 5?

14

描述:

我想在 Eclipse (Oxygen 4.7.1a) 中使用 JUnit 5 创建一个 JUnit 测试。这个测试应该在名为 Test 的单独的 src 文件夹中。但是,由于我对 JUnit 和 Java 9 还很陌生,所以我遇到了以下问题。

我不想 使用像 Gradle 或 Maven 这样的构建工具。

问题:

我有两个不同的 src 文件夹,一个用于项目的 src,另一个用于测试用例:

  • 我需要两个 module-info.java 文件吗?(每个 src 文件夹一个)
  • 在我的 module-info.java 文件中需要哪些模块才能让 JUnit 5 正常工作?

Maven(构建工具)使用src/main/java/src/test/java/,因此您可以在一个Maven项目中尝试它-遵循新的“最佳实践”。确实有一个问题https://dev59.com/IlgR5IYBdhLWcg3wZcq1 - Joop Eggen
可能是将Java 8项目迁移到Jigsaw时应将单元测试放在哪里的重复问题?Nicolai提出的解决方案应该可以帮助您。此外,不确定为什么特别标记了Junit5,因为对于任何类型的单元测试,结构应该是类似的。 - Naman
也希望@AlanBateman能够解释一下背景... 我希望工具、插件和测试运行程序能够提供支持,这样普通开发人员就不需要关心这个问题了。 也许我在邮件中完全错过了这个主题。 - Naman
@nullpointer 这不是重复问题,因为你链接的问题使用了Maven。 JUnit 5被标记为最新版本的JUnit,从我所读的内容来看,有很多变化。JUnit 5也已经针对Java 9进行了测试。 - ShadowDragon
这两个问题都采用了类似的方法,使用Java和Javac并修补模块。链接的问题已经得到了一般性的回答,无论构建框架如何实现这种方法。此外,JUnit5已经针对Java9进行了测试,并且有很多变化。那么,这是否意味着应该在问题中标记JUnit5? - Naman
显示剩余2条评论
2个回答

8
一般情况下,没有必要将测试代码模块化(至少我想不到一个有效的理由,也许有人可以给出令人满意的反例)。只有一个module-info.java文件可以存在于src下的主代码中(毕竟甚至没有必要将您的主代码模块化)。
由于module-info.java文件仅存在于主源目录中而不是测试源目录中,因此它在逻辑上不应依赖于JUnit模块。那么现在的问题就变成了如何通过依赖于代表被测试系统和JUnit模块的模块来编译和运行JUnit测试类。
为此,您需要使用javacjava提供的新选项:
假设您具有以下树形结构:
src
    module-info.java (declares a module called "my.module")
    mypackage
        MyClass.java
test_src
    mypackage
        MyClassTest.java
lib/junit-platform-console-standalone.jar

(注:特别针对JUnit 5,您可以使用包含核心JUnit引擎并允许在控制台中运行测试的junit-platform-console-standalone构件;请参见用户指南

然后,您可以按以下方式编译代码:

cd root_dir
javac -d mods/my.module src/module-info.java src/mypackage/MyClass.java

cd test_src
javac -d test_out --module-path ../mods;../lib/junit-platform-console-standalone.jar \
--add-modules org.junit.platform.console.standalone,my.module --patch-module my.module=. \
--add-reads my.module=org.junit.platform.console.standalone mypackage/MyClass.java

你可以运行已编译的测试类:

cd test_src/test_out
java --module-path=../../mods;../../lib/junit-platform-console-standalone.jar \
--add-modules my.module,org.junit.platform.console.standalone \
--add-reads my.module=org.junit.platform.console.standalone \
--patch-module my.module=. \
--add-opens my.module/test=org.junit.platform.console.standalone \ 
org.junit.platform.console.ConsoleLauncher test.MyClassTest

命令有些别扭,但这是不使用Maven的代价。我建议您在理解模块路径概念后阅读命令文档中有关这些选项的信息。需要注意的一点是有几个选项:

--patch-module my.module=.

这是必需的,因为示例测试代码与模块my.module具有相同的包(mypackage)。没有它,模块系统会报错。
--add-reads my.module=org.junit.platform.console.standalone

即使在module-info.java中没有声明,这也使得JUnit成为my.module所必需的。

org.junit.platform.console.standalone自动模块的名称,它源自于Jar清单(就像JUnit 5一样),否则源自于Jar文件的名称(例如,在JUnit 4的情况下)。

还要注意,这就是Maven在编译和运行单元测试时可能在后台执行的操作(请参见this issue以获取手动执行上述操作的等效插件配置)。

如果由于某种原因,您还想将单元测试模块化怎么办?

在这种情况下,由于上面的示例中单元测试共享相同的包,因此可以将它们包含在my.module中并添加对JUnit的要求:

module my.module {
    exports mypackage;
    requires org.junit.platform.console.standalone;
}

如果单元测试在不同的包中,您还可以将它们拆分为两个模块(两个module-info.java),一个my.module和一个my.test.module,只有后者需要JUnit。
如果在模块中包含测试类,则在上述命令中,您不需要--add-reads--patch-module

1
在最后一点上,JUnit在JAR清单中具有“Automatic-Module-Name”属性(即不是文件名)- https://github.com/junit-team/junit5/commit/a50e60aa64ecd1f7357409ab34ccd0964e9bee3b - Michael Easter
(1) 那似乎没有涉及junit5。 (2) 它不应该依赖于JUnit模块,为什么? - Naman
@MichaelEaster 不好意思,我之前在尝试使用JUnit 4的示例时忘记了这个问题的上下文。现在已经更新了,感谢您的纠正。 - M A
@nullpointer 我已经更新了关于JUnit 5自动模块的注释。对于依赖项,如果测试代码和主模块是分开的,为什么主模块需要JUnit呢?关键字“requires”意味着模块中的类需要它。 - M A
1
@nullpointer 很好。我从未说过测试不应该是模块的一部分 :) 只是我想不出为什么有人会这样做的有效理由,所以我没有理由为我的“无需将测试模块化”声明提供理由。 - M A
显示剩余6条评论

0
测试模块独立存在的原因是六边形架构。测试模块是一个驱动适配器,可以与运行业务逻辑的其他适配器交换使用。
在我的情况下,我将使用jaba 9进行操作,而不使用maven。
以下是我关于六边形架构的文章:

https://softwarecampament.wordpress.com/portsadapters/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接