【问题标题】:Running spock unit tests with Maven使用 Maven 运行 spock 单元测试
【发布时间】:2026-01-05 14:45:02
【问题描述】:

在之前的项目中,我使用 Spock 测试框架对我的 Java 代码进行单元测试。我发现这非常有成效,所以我尝试将 Spock 测试添加到我当前使用 Maven 作为构建工具的项目中(之前的项目使用 Gradle)。虽然我可以让 Maven 编译我的 Spock 测试(使用 groovy-eclipse-compiler),但我无法让 Maven 运行测试。

我做了一个简单的例子来演示我的问题与 2 个文件:

  • pom.xml
  • src/test/java/ASpec.groovy

pom.xml的内容:

<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>my.group</groupId>
    <artifactId>my-artifact</artifactId>
    <version>0.1-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
            <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>2.0.8</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.spockframework</groupId>
            <artifactId>spock-core</artifactId>
            <version>0.7-groovy-2.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <compilerId>groovy-eclipse-compiler</compilerId>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.codehaus.groovy</groupId>
                        <artifactId>groovy-eclipse-compiler</artifactId>
                        <version>2.8.0-01</version>
                    </dependency>
                    <dependency>
                        <groupId>org.codehaus.groovy</groupId>
                        <artifactId>groovy-eclipse-batch</artifactId>
                        <version>2.1.8-01</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
</project>

ASpec.groovy的内容:

import spock.lang.Specification

class ASpec extends Specification {

    def "Test A"(){
        // Always fail
        expect: false
    }
}

当我执行mvn clean test(或mvn clean install)时,我希望我的单个单元测试能够运行并失败。编译时,Maven 不会运行它。 有谁知道如何从 Maven 运行 Spock 单元测试(或者如果可能的话?)

(我没有将我的测试放在一个包中以保持示例的简单性。此外,我已将我的 groovy 代码放在 src/test/java 以避免将示例配置为从其他目录中获取源文件,再次保持示例尽可能简单。)

【问题讨论】:

    标签: java unit-testing maven groovy spock


    【解决方案1】:

    我遇到的一个问题是依赖不兼容。

    spock-core 依赖当然引入了它需要的 groovy 版本的依赖。但有可能其他依赖项或插件(我认为gmaven-plus 插件在我的例子中)引入了不同的、不兼容的 groovy 版本。

    我通过显式提供对我想使用的 groovy 包的依赖来解决问题。

    【讨论】:

      【解决方案2】:

      我有同样的要求将 Spock 添加到我现有的 Java Web 应用程序中。 我试过彼得斯,但它对我不起作用。 gmavenplus-plugin 不知何故(不知道)用一个非常旧的 google lib 替换了我的 guava 依赖项,我的 Spring 应用程序因抱怨不存在的方法而崩溃了。

      实际上大概 2 或 3 次尝试之后,我终于能够集成我的 Spock 单元测试和集成测试,更重要的是,将 Spock groovy 类的编译与我现有的 Java/Junit Spring/Hibernate 应用程序隔离开来。

      当然,如果我有 gradle,它会解决问题……但这是一个遗留项目,因此我别无选择。

      以下是我添加的插件。 请注意 Spock 单元测试以 Spec 结尾。 Spock 集成测试以 IT 结束(但很可能应该是 SpecIT)。 我将 Spock 测试放在 src/test/groovy 下。

               <plugins>
                  <plugin>
                      <groupId>org.codehaus.gmavenplus</groupId>
                      <artifactId>gmavenplus-plugin</artifactId>
                      <version>1.4</version>
                      <executions>
                          <execution>
                              <!-- Without joint compilation - no dependencies between Java and Groovy (inheritance)-->
                              <goals>
                                  <goal>testCompile</goal>
                              </goals>
                          </execution>
                      </executions>
                      <configuration>
                          <sources>
                              <source>
                                  <directory>${project.basedir}/src/main/java/groovy</directory>
                                  <includes>
                                      <include>**/*.groovy</include>
                                  </includes>
                              </source>
                          </sources>
                          <testSources>
                              <testSource>
                                  <directory>${project.basedir}/src/test/groovy</directory>
                                  <includes>
                                      <include>**/*.groovy</include>
                                  </includes>
                              </testSource>
                          </testSources>
      
                      </configuration>
                  </plugin>
                  <plugin>
                      <artifactId>maven-surefire-plugin</artifactId>
                      <version>2.18.1</version>
                      <configuration>
                          <testSourceDirectory>src/test/groovy</testSourceDirectory>
                          <testSourceDirectory>src/test/java</testSourceDirectory>
                          <includes>
                              <include>**/*Spec.java</include>
                              <!-- Yes, .java extension -->
                              <include>**/*Test.java</include>
                              <!-- Just in case having "normal" JUnit tests -->
                          </includes>
                      </configuration>
                  </plugin>
                  <plugin>
                      <groupId>org.apache.maven.plugins</groupId>
                      <artifactId>maven-failsafe-plugin</artifactId>
                      <version>2.20</version>
                      <configuration>
                          <useFile>false</useFile>
                          <includes>
                              <include>**/*IT.java</include>
                          </includes>
                      </configuration>
                      <executions>
                          <execution>
                              <goals>
                                  <goal>integration-test</goal>
                                  <goal>verify</goal>
                              </goals>
                          </execution>
                      </executions>
                  </plugin>
              </plugins>
      

      这是我的依赖项:

              <!--Spock -->
              <dependency>
                  <groupId>org.codehaus.groovy</groupId>
                  <artifactId>groovy</artifactId>
                  <version>2.4.7</version>
                  <scope>test</scope>
              </dependency>
      
              <dependency>
                  <groupId>org.spockframework</groupId>
                  <artifactId>spock-core</artifactId>
                  <version>1.1-groovy-2.4</version>
              </dependency>
      
              <dependency>
                  <groupId>org.spockframework</groupId>
                  <artifactId>spock-spring</artifactId>
                  <version>1.1-groovy-2.4</version>
              </dependency>
      
              <dependency>
                  <groupId>org.codehaus.groovy.modules.http-builder</groupId>
                  <artifactId>http-builder</artifactId>
                  <version>0.7.1</version>
              </dependency>
              <!--Spock mocking dependencies -->
              <dependency>
                  <groupId>cglib</groupId>
                  <artifactId>cglib-nodep</artifactId>
                  <version>3.2.5</version>
              </dependency>
              <dependency>
                  <groupId>org.objenesis</groupId>
                  <artifactId>objenesis</artifactId>
                  <version>2.6</version>
              </dependency>
      

      只是让你知道,我原来的 POM 完全没有明确的插件。所以我的项目有一个非常简单的 POM。所以,它应该为你工作。 这是一个 Java 1.7 项目。

      ...最后,为了让您确信这不是一篇垃圾帖子,我进行了多次测试以确保上述方法有效:

      1. 只需构建没有测试的 WAR,然后在本地部署和冒烟测试
        mvn clean install -DskipTests -Dmaven.test.skip=true

      2. 进行测试编译,看看 Groovy 单元测试是否也被编译
        mvn -X clean test-compile

      3. 在没有集成测试的情况下进行全新安装(我确保它在此测试中失败)并查看 Groovy 单元测试是否运行
        mvn clean install -DskipITs em>

      4. 只需运行集成测试
        mvn failsafe:integration-test

      我希望将上述截图作为证据,但必须对其进行审查...所以,我真诚地希望这对您有所帮助,因为我正在努力使这项工作发挥作用...Maven 是一个巨大的学科领域。祝你好运:=)

      【讨论】:

        【解决方案3】:

        此答案纯粹是对@PeterNiederwieser 答案的补充。在其中他提到您可以配置 Surefire 使用的名称模式。以下是对我有用的示例:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.18</version>
            <configuration>
                <includes>
                    <!-- By default only files ending in 'Test' will be included, so also include support for Spock style naming convention -->
                    <!-- Oddly enough for Groovy files, *Spec.groovy does not work, but *Spec.java does -->
                    <include>**/*Test.java</include>
                    <include>**/*Spec.java</include>
                </includes>
            </configuration>
        </plugin>
        

        Source

        正如我在 cmets 中提到的,我不确定为什么 **/*Spec.groovy 不起作用,但我很高兴能够在这里使用正常的 Spock 约定。

        【讨论】:

        • 请注意,如果您想包含 JUnit 通常找到的所有测试,您需要包含“**/Test*.java”、“**/*Test.java”和“**/*TestCase.java”,根据Surefire plugin documentation.
        • 即使我的规范文件扩展名是.groovy,也要提出关于使用**/*Spec.java的评论
        【解决方案4】:

        Maven Surefire 按名称查找测试类。要么将类名更改为ATest,要么重新配置 Surefire 使用的名称模式。 spock-example 项目的 POM 演示了如何执行后者。

        【讨论】:

        • @Peter 为什么**/*Spec.java 有效而**/*Spec.groovy 无效?
        • @Vajda 不是答案,但您可以使用 **/*Spec.class