【发布时间】:2020-03-18 19:47:04
【问题描述】:
刚刚开始一个新的 Gradle 项目。
此测试通过:
def 'Launcher.main should call App.launch'(){
given:
GroovyMock(Application, global: true)
when:
Launcher.main()
then:
1 * Application.launch( App, null ) >> null
}
...直到,为了使用 (Java) Mock 进行另一个测试,我必须添加这些依赖项:
testImplementation 'net.bytebuddy:byte-buddy:1.10.8'
testImplementation 'org.objenesis:objenesis:3.1'
(注意,我假设这些版本适用于 Groovy 3.+,我现在正在使用它......两者都是 Maven Repo 上提供的最新版本)。
由于这些依赖项,上述测试失败:
java.lang.InstantiationError: javafx.application.Application
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:48)
at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
at org.objenesis.ObjenesisHelper.newInstance(ObjenesisHelper.java:44)
at org.spockframework.mock.runtime.MockInstantiator$ObjenesisInstantiator.instantiate(MockInstantiator.java:45)
at org.spockframework.mock.runtime.MockInstantiator.instantiate(MockInstantiator.java:31)
at org.spockframework.mock.runtime.GroovyMockFactory.create(GroovyMockFactory.java:57)
at org.spockframework.mock.runtime.CompositeMockFactory.create(CompositeMockFactory.java:42)
at org.spockframework.lang.SpecInternals.createMock(SpecInternals.java:47)
at org.spockframework.lang.SpecInternals.createMockImpl(SpecInternals.java:298)
at org.spockframework.lang.SpecInternals.createMockImpl(SpecInternals.java:288)
at org.spockframework.lang.SpecInternals.GroovyMockImpl(SpecInternals.java:215)
at core.AppSpec.Launcher.main should call App.launch(first_tests.groovy:30)
我承认我对“bytebuddy”和“objenesis”的实际作用只有最粗略的概念,尽管我认为它非常聪明。编辑:刚刚访问了他们各自的主页,我的想法现在稍微不那么粗略了,是的,它非常聪明。
如果没有可用的正统解决方案,是否有可能关闭对单个功能(即测试)的这些依赖项的使用?可能会使用一些注释吗?
编辑
这是一个 MCVE: 规格:Java 11.0.5,操作系统 Linux Mint 18.3。
build.gradle:
plugins {
id 'groovy'
id 'java'
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.8'
}
repositories { mavenCentral() }
javafx {
version = "11.0.2"
modules = [ 'javafx.controls', 'javafx.fxml' ]
}
dependencies {
implementation 'org.codehaus.groovy:groovy:3.+'
testImplementation 'junit:junit:4.12'
testImplementation 'org.spockframework:spock-core:2.0-M2-groovy-3.0'
testImplementation 'net.bytebuddy:byte-buddy:1.10.8'
testImplementation 'org.objenesis:objenesis:3.1'
// in light of kriegaex's comments:
implementation group: 'cglib', name: 'cglib', version: '3.3.0'
}
test { useJUnitPlatform() }
application {
mainClassName = 'core.Launcher'
}
installDist{}
main.groovy:
class Launcher {
static void main(String[] args) {
Application.launch(App, null )
}
}
class App extends Application {
void start(Stage primaryStage) {
}
}
first_tests.groovy:
class AppSpec extends Specification {
def 'Launcher.main should call App.launch'(){
given:
GroovyMock(Application, global: true)
when:
Launcher.main()
then:
1 * Application.launch( App, null ) >> null
}
}
这个项目需要调用Application 子类的原因解释了here:这样就可以在JavaFX 中进行捆绑的installDist。
【问题讨论】:
-
当您使用的 Groovy 版本不存在正式的 Spock 版本时,您的确切设置将比平时更有趣,MCVE - 是的,我再次要求它,你记得我 - 是你应该提供的。例如,您甚至没有提及您使用的是哪个 Spock 预发布版本,例如2.0-M2-groovy-3.0 本身依赖于 cglib 3.2.10、bytebuddy 1.9.11 和 objenesis 3.0.1,在首次设置前沿类型的项目时最好坚持使用它们。你的 Java 版本是什么?
-
顺便说一句,如果您需要一个 Groovy 模拟,尤其是全局模拟,那么您的应用程序设计可能有问题,您应该重构以便更容易注入
Applicaction模拟你的Launcher。 -
谢谢,这些 cmets 非常有帮助。请参阅编辑:MCVE。如果您可以建议某种类型的重构也将有所帮助:问题在于 Gradle 的
application插件需要一个“主类”,而Application.launch()也是static。我们不是必须使用全局GroovyMock吗?说任何使用 Groovy 模拟是错误的,这不是有点极端吗? -
最后一件事:您说 Spock spock-core:2.0-M2-groovy-3.0 是“预发布”。我在此页面 (mvnrepository.com/artifact/org.spockframework/spock-core/…) 上看不到任何内容。你怎么知道的?顺便说一句,我还尝试了该页面上声明的 bytebuddy、objenesis 和 cglib 的版本:同样的错误。
-
啊,是的,在这里看到了:github.com/spockframework/spock/releases。我切换回 Groovy 2.5.9 和 Spock 1.3,摆脱了
test { useJUnitPlatform() },为 Spock 1.3 使用了 bytebuddy、objenesis 和 cglib 的“正确”版本:同样的错误。
标签: groovy mocking spock byte-buddy objenesis