我们应该考虑从@ExpectedException
AssertJ迁移。如果/当我们升级到 JUnit 5 时这将会有所帮助。
[spring-projects/spring-boot]从 ExpectedException 规则迁移到 AssertJ
回答
嗨@philwebb,我是新来的,很乐意解决这个问题。我很清楚,这个问题涉及修改所有使用@ExpectedException
相应 AssertJ 替代方案的测试,对吗?也就是说,这对用户与框架交互的方式没有影响,对吗?
@ivange94 非常感谢您提供帮助。你是对的,这里的目的是删除我们对等价物的ExpectedException
使用AssertJ
。
@snicoll 感谢您的快速回复。我正在继续开展这方面的工作。
当我使用./mvnw clean install构建新克隆时,测试失败
[INFO] Running org.springframework.boot.SpringApplicationTests
[ERROR] Tests run: 75, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 1,117.157 s <<< FAILURE! - in org.springframework.boot.SpringApplicationTests
[ERROR] failureResultsInSingleStackTrace(org.springframework.boot.SpringApplicationTests) Time elapsed: 6.018 s <<< FAILURE!
org.junit.ComparisonFailure: [Expected single stacktrace] expected:<[1]> but was:<[0]>
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at org.springframework.boot.SpringApplicationTests.failureResultsInSingleStackTrace(SpringApplicationTests.java:1168)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.springframework.boot.testsupport.rule.OutputCapture$1.evaluate(OutputCapture.java:57)
at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:365)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:273)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:238)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:159)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:383)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:344)
当我尝试从 IDE (InteliJ Idea) 运行测试时,我得到了
Error:java: Bad service configuration file, or exception thrown while constructing Processor object: javax.annotation.processing.Processor: Provider org.springframework.boot.configurationprocessor.ConfigurationMetadataAnnotationProcessor not found
我已经对想法错误和解决方案进行了一些研究,我发现这些错误和解决方案需要我对项目进行一些修改,所以我想我正在寻找错误的地方,因为所有这些都必须适用于其他人。
@ivange94 你使用什么操作系统?
@philwebb macOS Sierra (10.12.6)
@ivange94 这应该可以找到。java -version
和显示什么echo $JAVA_HOME
?
java -版本显示
Ivanges-MacBook-Pro:~ ivange$ java -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
JAVA_HOME 未设置。
@ivange94 我有点不知所措。您可以尝试设置 aJAVA_HOME
但我认为它不会解决您所看到的测试失败问题。我现在不太确定该建议什么。
@philwebb 没有。
@ivange94 真糟糕。也许您可以加入我们的 Gitter,我们可以尝试找出您的机器上发生了什么?
@snicoll 听起来很棒。不知道还有 gitter 频道。请问我怎样才能加入?
@snicoll 找到了该频道。我们将在那里继续讨论。
代码库中有超过一千种 ExpectedException 的用法。我是否可以在提交 PR 之前重构整个代码库,或者可以提交小型 PR?我已经完成了 spring-boot-project 中 spring-boot 子项目的重构,这已经是 66 个文件的修改,其中添加了 425 个文件,删除了 855 个文件。
我还有超过 12 个子项目需要重构。
感谢您查看此内容,@ivange94。在继续之前,我们应该确定要使用的语法。 AssertJ 提供两种选择:
@Test
public void testException() {
assertThatThrownBy(() -> { throw new Exception("boom!"); }).isInstanceOf(Exception.class)
.hasMessageContaining("boom");
}
@Test
public void testException() {
assertThatExceptionOfType(IOException.class).isThrownBy(() -> { throw new IOException("boom!"); })
.withMessage("%s!", "boom")
.withMessageContaining("boom")
.withNoCause();
}
就第一印象而言,我认为第二个选项读起来更好。让我们看看团队其他成员的想法,以便我们能够就使用哪种方案达成一致。
+1 为assertThatExceptionOfType
. javadoc 还说它或多或少与 相同,assertThatThrownBy
但方式更自然。
相同的。我喜欢assertThatExceptionOfType
。
ExpectedException 有一千多种用法
我想知道我们是否可以以某种方式编写迁移脚本?也许我们可以使用 Atomist 的 AST 转换支持。
我还发现assertThatExceptionOfType感觉更自然,这就是我一直在使用的。
我想知道我们是否可以以某种方式编写迁移脚本?也许我们可以使用 Atomist 的 AST 转换支持。
@philwebb 自动化听起来很棒,但我不确定我是否确切知道 AST 转换支持的含义。 AssertJ 作者创建了一个迁移脚本,但我没有想到使用它的原因是该脚本最终可能会更改很多内容,而不仅仅是 ExpectedException。您能阐明一下您的方法吗?
这些文档有点简单,我还没有使用过它,但 Atomist 有一些聪明的功能,它可以根据代码结构而不是原始文本来编辑文件。 AST 代表抽象语法树,它基本上意味着您可以根据解析的文本而不是文本本身来更改内容。
我们的大多数测试看起来都是这样的:
@Test
public void createWhenEndpointTypeIsNullShouldThrowException() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("EndpointType must not be null");
new ExposeExcludePropertyEndpointFilter<>(null, new MockEnvironment(), "foo");
}
我们需要从调用中提取IllegalArgumentException.class
和 ,然后将方法的其余部分设为 lambda 并以某种方式将其重新修改为:"EndpointType must not be null"
this.thrown
@Test
public void createWhenEndpointTypeIsNullShouldThrowException() {
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(()-> {
new ExposeExcludePropertyEndpointFilter<>(null, new MockEnvironment(), "foo");
}).withMessageContaining("EndpointType must not be null");
}
我是新来的,很乐意解决这个问题
@ivange94 我非常感谢您提供的帮助,但这可能是一个相当大且耗时的更改。如果您有时间,请继续调查,但ideal-for-contribution
如果您想从挑战性较小的事情开始,也可以随时查看状态标签。
@philwebb,你是对的,这是一个耗时的改变。一遍又一遍地做同样的事情会变得无聊。我会看一下标签,但仍会继续努力。如果能让脚本正常工作,否则我会手动完成。
@ivange94 感谢您提供帮助,但我现在已经成功地使用搜索/替换、正则表达式、重构和纯粹的意志力的组合来迁移测试:)