从 Spring Boot 2.6.4 升级到 2.6.6 时,我的一项测试(用 Kotlin 编写)失败了:
@Test
fun shouldLogProperMessageIfNotAbleToHitAPI() {
val configValidator = ConfigValidator(GitHubCrawlerProperties(SourceControlConfig(url = "someIncorrectURL",organizationName="someOrg")),mockRemoteSourceControl)
`when`(mockRemoteSourceControl.validateRemoteConfig("someOrg")).thenThrow(NoReachableRepositories("problem !",mock(Exception::class.java)))
val validationErrors=configValidator.getValidationErrors()
assertThat(validationErrors).hasSize(1);
}
构建通过 Spring Boot 2.6.4。当我在我的 IDE 中单独运行测试时,它在 Spring Boot 2.6.6 中工作,但在 Maven 构建期间失败。
stacktrace 默认情况下没有显示,但是在用 try/catch 包围调用之后,我能够得到它,它指向 Logback :
java.lang.NullPointerException: null
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:99)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:89)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:62)
at ch.qos.logback.classic.spi.LoggingEvent.<init>(LoggingEvent.java:119)
at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:419)
at ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:383)
at ch.qos.logback.classic.Logger.error(Logger.java:538)
at com.societegenerale.githubcrawler.ConfigValidator.getValidationErrors(ConfigValidator.kt:48)
Logback 版本似乎没有变化,我仍然得到 v 1.2.11 .
查看 Logback 源代码,在 ThrowableProxy 中:
if (GET_SUPPRESSED_METHOD != null) {
// this will only execute on Java 7
Throwable[] throwableSuppressed = extractSupressedThrowables(throwable);
if (throwableSuppressed.length > 0) {
List<ThrowableProxy> suppressedList = new ArrayList<ThrowableProxy>(throwableSuppressed.length);
for (Throwable sup : throwableSuppressed) {
...
注意:我使用 Java 11 构建,所以 Logback 源代码中的评论说
this will only execute on Java 7
似乎是错误的。
好像
throwableSuppressed
是空的,当throwableSuppressed.size
被调用时我得到了NPE。
如果我没有在
NoReachableRepositories("problem !",mock(Exception::class.java))
中使用模拟,而是使用 NoReachableRepositories("problem !",Exception())
,则测试通过
我意识到使用真正的异常可能比模拟更好,所以我的问题以某种方式解决了(在这上面花了 2 个小时之后......)。
但是,我很好奇:升级到 Spring Boot 2.6.6 后会导致这个问题,这应该是一个小改动?
这个问题是在
logback:1.2.11
中由这个commit引入的。它在这个 Jira ticket 中被跟踪。
Logback
从 spring boot 2.6.5 升级到 1.2.11,你可以参考这个 changelog。所以如果你升级到 2.6.5,你会遇到同样的错误。
我们现在可以做的是通过在
logback
文件中添加这一行来将 build.gradle
的版本覆盖到 1.2.10。
ext["logback.version"] = "1.2.10"
如果您使用 Maven
dependencyManagement
部分来获取 Spring Boot 依赖项而不是启动器父项,那么您可以试试这个:
<!-- ... -->
<dependencyManagement>
<dependencies>
<!-- temp. override logback version for https://jira.qos.ch/browse/LOGBACK-1623-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.2.10</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.10</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.7.5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencyManagement>
<!-- ... -->
更新:Spring Boot 2最新版本(2.7.5)仍在使用
logback:1.2.11
.
如果只是为了测试你可以模拟 LoggerFactory
try (MockedStatic<LoggerFactory> loggerFactoryMock = Mockito.mockStatic(LoggerFactory.class)) {
loggerFactoryMock.when(() -> LoggerFactory.getLogger(any(Class.class))).thenReturn(Mockito.mock(Logger.class));
// your code
}