Spring Boot 2.6.4 -> 2.6.6:记录模拟异常时 Logback 中出现奇怪的 NullPointerException

问题描述 投票:0回答:2

从 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 后会导致这个问题,这应该是一个小改动?

java spring-boot kotlin mockito logback
2个回答
12
投票

这个问题是在

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
.


0
投票

如果只是为了测试你可以模拟 LoggerFactory

        try (MockedStatic<LoggerFactory> loggerFactoryMock = Mockito.mockStatic(LoggerFactory.class)) {
            loggerFactoryMock.when(() -> LoggerFactory.getLogger(any(Class.class))).thenReturn(Mockito.mock(Logger.class));
            // your code
        }
© www.soinside.com 2019 - 2024. All rights reserved.