刚刚开始一个新的项目。
此测试通过:
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)我承认,我对“字节伙伴”和“讣告”实际上所做的事情只有一个最粗略的概念,尽管我认为它非常聪明。编辑:刚刚访问了他们各自的主页后,我的想法现在稍微不那么粗略了,是的,这是非常聪明的。
如果对此没有正统的解决方案,那么是否有可能将这些依赖关系用于单独的特性(即测试)?可能会使用注释吗?
编辑
这是一个MCVE: Specs: Java11.0.5,OSLinuxMint18.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了。
发布于 2020-03-20 03:40:57
,难道我们不需要使用全局GroovyMock吗?
如果你想检查互动,是的。但实际上,您是在测试JavaFX启动程序,而不是应用程序。因此,我怀疑是否有任何好处。我将重点放在测试App类上。还可以想象一下,您将用Java而不是Groovy的主要方法编写类。当从Java代码调用Groovy模拟时不能工作,尤其是全局代码。然后,您将通过Spock的Powermockito进行测试,这也可以工作,但您仍然会测试JavaFX启动程序,而不是应用程序。
也说--任何使用Groovy模拟的--都是错误的,这不是有点极端吗?
我可没那么说。我说:“可能应用程序设计有问题”。我之所以这么说,是因为Groovy模拟的使用以及类似模拟静态方法之类的东西都是测试代码的味道。你可以检查气味,然后判断它是否正常,而在大多数情况下,它不是。此外,除了应用程序设计之外,问题还可以发生在测试本身,在这种情况下,我可以这样说。但这是有争议的,所以我将在下面向你们提出一个解决方案。
在这种情况下,从技术上讲,全局Application模拟是唯一的方法,如果您坚持测试JavaFX启动程序,因为即使是App上的全局模拟也不能工作,因为启动程序使用反射来调用App构造函数,并且模拟框架不会拦截这一点。
你说斯波克-核心:2.0-M2-Groovy-3.0是一个“预发行版”。我在这页上什么也看不见(.)上面写着。怎么又知道了?
您已经通过查看GitHub存储库了解到了这一点,但我刚才看到的是不寻常的版本号,其中包含"M2“之类的”里程碑2“,类似于用于发布候选版本(或候选版本)的"RC”(或"CR")。
至于技术问题,您既不能在Gradle脚本中声明Objenesis,因为它是一个可选的依赖项,那么测试就会编译并运行良好,正如您已经注意到的那样。但是,假设您需要Objenesis、CGLIB (实际上是cglib)、Bytebuddy和ASM这样的可选依赖项来进行您的套件中的其他测试,那么您只需告诉Spock在本例中不要使用Objenesis。因此,假设您有一个如下所示的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 'org.spockframework:spock-core:2.0-M2-groovy-3.0'
// Optional Spock dependencies, versions matching the ones listed at
// https://mvnrepository.com/artifact/org.spockframework/spock-core/2.0-M2-groovy-3.0
testImplementation 'net.bytebuddy:byte-buddy:1.9.11'
testImplementation 'org.objenesis:objenesis:3.0.1'
testImplementation 'cglib:cglib-nodep:3.2.10'
testImplementation 'org.ow2.asm:asm:7.1'
}
test { useJUnitPlatform() }
application {
mainClassName = 'de.scrum_master.app.Launcher'
}
installDist {}我的MCVE版本应该是这样的(对不起,我添加了自己的包名并导入,因为否则它实际上不是MCVE):
package de.scrum_master.app
import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.control.Label
import javafx.scene.layout.StackPane
import javafx.stage.Stage
class App extends Application {
@Override
void start(Stage stage) {
def javaVersion = System.getProperty("java.version")
def javafxVersion = System.getProperty("javafx.version")
Label l = new Label("Hello, JavaFX $javafxVersion, running on Java $javaVersion.")
Scene scene = new Scene(new StackPane(l), 640, 480)
stage.setScene(scene)
stage.show()
}
}package de.scrum_master.app
import javafx.application.Application
class Launcher {
static void main(String[] args) {
Application.launch(App, null)
}
}package de.scrum_master.app
import javafx.application.Application
import spock.lang.Specification
class AppSpec extends Specification {
def 'Launcher.main should call App.launch'() {
given:
GroovyMock(Application, global: true, useObjenesis: false)
when:
Launcher.main()
then:
1 * Application.launch(App, null)
}
}这里的决定性细节是useObjenesis: false参数。
更新:仅供参考,您将使用使用PowerMockito实现的launcher类来实现它。
请注意,此解决方案需要在2.x中删除的Spok1.x中的Sputnik运行程序。因此,在Spock 2中,这目前无法工作,因为它基于JUnit 5,并且不能再使用@RunWith(PowerMockRunner)和@PowerMockRunnerDelegate(Sputnik),因为PowerMock目前不支持JUnit 5。但是我用Spock 1.3-groovy-2.5和Groovy2.5.8测试了它。
package de.scrum_master.app
import javafx.application.Application
import org.junit.runner.RunWith
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
import org.powermock.modules.junit4.PowerMockRunnerDelegate
import org.spockframework.runtime.Sputnik
import spock.lang.Specification
import static org.mockito.Mockito.*
import static org.powermock.api.mockito.PowerMockito.*
@RunWith(PowerMockRunner)
@PowerMockRunnerDelegate(Sputnik)
@PrepareForTest(Application)
class JavaAppSpec extends Specification {
def 'JavaLauncher.main should launch JavaApp'() {
given:
mockStatic(Application)
when:
JavaLauncher.main()
then:
verifyStatic(Application, times(1))
Application.launch(JavaApp)
}
}https://stackoverflow.com/questions/60746571
复制相似问题