在库中的代码内部调用Groovy Mocked方法时返回null

r7knjye2  于 2022-11-01  发布在  其他
关注(0)|答案(1)|浏览(182)

我正在开发一个包含多个模块的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)。

gijlo24d

gijlo24d1#

你不能用Spock来模拟Java的final类,而且GroovyMock只对用(动态的)Groovy编写的代码有效。
然而,有一个扩展spock-mockable,它将使用java代理从配置的类、方法和字段中透明地删除final修饰符。使用这个扩展,您可以使用Spock的标准Mock方法来模拟现在非final的类。

@Mockable(MyClass1)
class ASpec extends Specification {

def "unsuccessful test"() {
  given:
  MyClass1 myMock1 = Mock() // 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 ""
}
}

相关问题