打开在配置 class 中声明的 bean

Opening bean declared in Configuration class

最近我遇到了 Spring、Kotlin 和 Spock 的奇怪问题。我有非常简单的项目(spring-boot,spring-web)。我有一个 Controller,其中很少 Bean 注入到这个 Controller。一切正常。问题在测试中。我无法模拟这些 Bean 中的任何一个。 kotlin-spring/kotlin-allopen 不会向 Configuration class 中定义的 bean 添加 open 签名。另一方面,如果我将此声明更改为 @Component 一切正常。

这是我的 build.gradle.kts 插件列表

plugins {
    id("idea")
    id("groovy")
    id("maven-publish")
    id("org.springframework.cloud.contract") version "2.2.5.RELEASE"
    id("org.springframework.boot") version "2.4.1"
    id("io.spring.dependency-management") version "1.0.10.RELEASE"
    kotlin("jvm") version "1.4.21"
    kotlin("plugin.spring") version "1.4.21"
    kotlin("plugin.allopen") version "1.4.21"
}

这是错误信息:

Caused by: org.spockframework.mock.CannotCreateMockException: Cannot create mock for class *** because Java mocks cannot mock final classes. If the code under test is written in Groovy, use a Groovy mock.

我知道它说我可以使用 GroovyMock 但我想在测试中设计我的基础 class 并且我想使用 @TestConfiguration class。所以为了模拟那些 classes 我想使用 DetachedMockFactory.

有没有办法将 Spock 配置为能够模拟来自 Kotlin 的最终 classes?或者有没有办法告诉 kotlin-spring/kotlin-allopen 打开 classes 在 Configuration class?

中定义为 beans

编辑:

我的示例项目在这里: https://github.com/czyzniek/bank/tree/with-spock

我无法帮你修复spock-mockable问题,也许你想向作者寻求帮助。最近我已经在那个项目中修复了一个 Maven 问题,但现在似乎有一个 ByteBuddy 问题,试图重新定义一个已经加载的 class,这在 JVM 中是不可能的。我相信维护者可以帮助你。

与此同时,就像我在之前的评论中建议的那样,为您切换到 Sarek solves the problem, though. I created a corresponding pull request

目前它使用默认的完整 Sarek 代理。如果您将 sarek-unfinal 添加为依赖项而不是 sarek ,并且还要确保在 属性 dev.sarek.agent.type=unfinal 中设置系统 Gradle Spock 测试的配置,您可以使用较小的 unfinal 代理而不使用其余的 Sarek 功能。 作为一个 Gradle 菜鸟,我不知道如何配置它。

更新: 不再需要上面提到的附加系统属性。最新的 Sarek 快照在 class 路径上时自动检测未最终代理(或 4 种 Sarek 代理中的任何其他类型)。我知道您已决定使用 spock-mockable,但我想让这个答案保持最新以供参考。参见 this diff for what the pull request would look like now, especially this simple commit

如果您目前在使用快照版本时遇到任何问题,请告诉我。如果这是一个商业项目,并且您需要构建一个在某些时候禁止使用快照版本的版本,我可以在 Maven Central 上发布 1.0 或 0.8 或其他任何版本。现在我只是将 Maven Central 快照存储库 (Sonatype OSS) 添加到您的构建中。

感谢大家的帮助! @kriegaex 您的解决方案非常有效,谢谢!

关于 spock-mockable,我与该库的作者进行了交谈,他弄清楚了为什么 spock-mockable 无法使用我的设置 (GH issue)。这是因为 spock-spring 扩展名。根本原因是 spock-spring 扩展在 spock-mockable 之前加载。当 Spring/Spock 想从 @TestConfiguration class 创建模拟时,它不能,因为 kotlin-spring 插件不会打开 classes 在 [=17] 中声明为 beans =] class 和 spock-mockable 此时未加载。笑话改变了他的扩展程序的加载方式,所以现在 spock-mockablesarek 两个解决方案都有效。

我相信我的问题就此结束 ;)