我正在开发一个包含多个模块的Java项目,我决定创建一个仅用于测试的Module,其中“java”文件夹是空的,“test”文件夹包含项目的所有单元和集成测试。
我在模拟MyClass1的getText的测试中遇到问题()方法。如果我调用getText,(),但是当从MyClass2的方法中调用它时,它返回null。我怀疑这与如何编译Groovy文件以允许方法模拟有关,而MyClass1和MyClass2已经编译过了,因为它们来自一个库。
第1单元中的类
public final class MyClass1 {
private String text;
public MyClass1() {
text = "Hello there!";
}
public String getText() {
return text;
}
}
public class MyClass2 {
private MyClass1 myObject1;
public MyClass2(MyClass1 myObject1) {
this.myObject1 = myObject1;
}
public String toLowerCase() {
return myObject1.getText().toLowerCase();
}
}
测试项目:
def assertTextNotNull(MyClass1 myObject1) {
assert myObject1.getText() != null;
}
def "successful test"() {
given:
MyClass1 myMock1 = GroovyMock(MyClass1);
myMock1.getText() >> "ABC";
assertTextNotNull(myMock1);
}
def "unsuccessful test"() {
given:
MyClass1 myMock1 = GroovyMock(MyClass1); // I need to use GroovyMock here because the actual class I'm mocking is final
MyClass2 myObject2 = new MyClass2(myMock1);
myMock1.getText() >> "ABC";
when:
assertTextNotNull(myMock1);
then:
myObject2.toLowerCase() == "abc"; // Fails here because myObject1.getText() returns an empty String ""
}
我的测试模块的pom:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>myGroupId</groupId>
<artifactId>myParentArtifactId</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>myArtifactId-tests</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>17</release>
</configuration>
<dependencies>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M7</version>
<configuration>
<excludes>
<exclude>**/*IT.*</exclude>
<exclude>**/*IntegrationTest.*</exclude>
</excludes>
<includes>
<include>**/*UT.*</include>
<include>**/*UnitTest.*</include>
<include>**/*UT.groovy</include>
</includes>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M7</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<excludes>
<exclude>**/*UT.*</exclude>
<exclude>**/*UnitTest.*</exclude>
</excludes>
<includes>
<include>**/*IT.*</include>
<include>**/*IntegrationTest.*</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<!-- The gmavenplus plugin is used to compile Groovy code. To learn
more about this plugin, visit https://github.com/groovy/GMavenPlus/wiki -->
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.13.1</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compileTests</goal>
<goal>addSources</goal>
<goal>addTestSources</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<repositories>
<repository>
<id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<!-- Paper/Waterfall -->
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.18.2-R0.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.github.waterfallmc</groupId>
<artifactId>waterfall-api</artifactId>
<version>1.18-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- All other modules -->
<dependency>
<groupId>myGroupId</groupId>
<artifactId>myArtifactId-module1</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<!-- Testing related -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
<!-- Enables mocking of classes without default constructor (together with CGLIB) -->
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>2.2-M1-groovy-4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.3.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
我在StackOverflow上搜索了很多地方。似乎人们只有在使用自己的代码时才会遇到模拟方法返回null的问题,而不是库代码。因此,我没有找到解决方案。
我可以做些什么来确保getText()返回模仿的回复,而不受调用它的位置的影响?
编辑:
有一个开发。我基本上复制粘贴我粘贴在这里的代码到一个新的模块,并使MyClass1 final就像它在库中一样。它没有工作,正如预期的那样。通过删除类声明上的final,测试突然工作了。所以,我可以得出的结论是,Mockingfinal类的方法只能在groovy代码中使用。其他模块的代码,但将返回一个默认值(在我的例子中,为null。在发布的代码的例子中,为空String)。
1条答案
按热度按时间gijlo24d1#
你不能用Spock来模拟Java的final类,而且
GroovyMock
只对用(动态的)Groovy编写的代码有效。然而,有一个扩展spock-mockable,它将使用java代理从配置的类、方法和字段中透明地删除
final
修饰符。使用这个扩展,您可以使用Spock的标准Mock
方法来模拟现在非final的类。