负载测试 Spock 规范,运行 并发多次

Load-test Spock spec, running it concurrently multiple times

我已经在 Spock 中编写了集成测试,我想将其重新用于负载测试。我没有以编程方式执行 Spock 测试的运气。我需要 运行 将整个规范作为一个单元并发执行以创建负载。

以前关于此主题的堆栈溢出帖子已过时(我试了很多都没有成功)。

规范示例:

class MySpec extends Specification { 
   def 'test'() {
      expect: 1+1 == 2
   }
}

我希望能够运行这样的(执行,成功和失败都是AtomicInteger):

executor.submit(() -> {
    try {
        executed.addAndGet(1);
        Result result = mySpecInstance.run() // <-- what should this be.
        if (result.wasSuccessful()) {
            succeeded.addAndGet(1);
        } else {
            failed.addAndGet(1);
            log.error("Failures encountered: {}", result.getFailures());
        }

    } catch (RuntimeException e) {
        log.error("Exception when running runner!", e);
        failed.addAndGet(1);
    }});
Invalid test class 'my.package.MySpec':
  1. No runnable methods]
groovy.lang.MissingMethodException: No signature of method: spock.util.EmbeddedSpecRunner.runClass() is applicable for argument types: (Class) values: [class my.package.MySpec]
Possible solutions: getClass(), metaClass(groovy.lang.Closure)

我正在使用带有 Groovy 3.0.4 和 spock-2.0-M3-groovy-3.0 (spock-junit4) 的 JDK8。

更新:

post 的答案适用于 Groovy-2.4、Spock-1.3,但不适用于 Groovy-3.0 和 Spock-2.0。

谢谢。

顺便说一句,您的错误并未发生,因为您使用了错误的 Spock 版本。如果你想 运行 旧的 JUnit 4 API,你可以使用模块 spock-junit4。我刚刚尝试过,该方法适用于 Spock 1 并且仍然适用于 Spock 2,即使您可能应该升级到不依赖旧 API 和兼容层的东西。

您的错误消息仅仅是因为您从其他答案中复制并粘贴了代码而没有修复它。那里的人写了 MySuperSpock.Class 导致错误,因为 if 必须是 MySuperSpock.class 和小写的“C”或者在 Groovy 下只是 MySuperSpock 因为 .class在那里是可选的。

错误消息甚至证明你在 class 路径上有 JUnit 4 并且一切正常,否则导入 JUnit 4 API classes 的代码将无法编译第一名。并且错误消息还解释了问题所在并提出了解决方案:

Exception in thread "main" groovy.lang.MissingPropertyException: No such property: Class for class: de.scrum_master.testing.MyTest
Possible solutions: class

看到了吗? Class MyTest 没有任何 属性 称为 Class。一种可能的解决方案(在本例中甚至是正确的解决方案)是使用 .class。这给了你一个提示。顺便说一句,语法 MyTest.Class 看起来像内部 class 引用或者可能是对编译器的 属性 引用(对我来说也是)。


更新: 我只是仔细看了看,注意到你说的另一个问题的解决方案适用于 Spock 1.3 实际上编译并且 运行s,但是JUnit 核心 运行ner 并没有真正地 运行 测试。 我尝试了打印一些东西的测试。此外,结果报告所有测试均失败。

对于简单的情况,您可以使用 Spock 的 EmbeddedSpecRunner,它在内部用于测试 Spock 本身。在 Spock 1.x 下,在测试 class 路径上安装 JUnit 4 就足够了,在基于 JUnit 5 平台的 Spock 2 下,您也需要添加这些依赖项,因为嵌入式 运行ner 使用它们:

<properties>
  <version.junit>5.6.2</version.junit>
  <version.junit-platform>1.6.2</version.junit-platform>
  <version.groovy>3.0.4</version.groovy>
  <version.spock>2.0-M3-groovy-3.0</version.spock>
</properties>

<!-- JUnit 5 Jupiter platform launcher for Spock EmbeddedSpecRunner  -->
<dependency>
  <groupId>org.junit.platform</groupId>
  <artifactId>junit-platform-launcher</artifactId>
  <version>${version.junit-platform}</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.junit.platform</groupId>
  <artifactId>junit-platform-testkit</artifactId>
  <version>${version.junit-platform}</version>
  <scope>test</scope>
</dependency>

然后你可以运行这样的测试:

def spockRunner = new EmbeddedSpecRunner()
def spockResult = spockRunner.runClass(MyTest)
println "Tests run: " + spockResult.runCount
println "Tests ignored: " + spockResult.ignoreCount
println "Tests failed: " + spockResult.failureCount

顺便说一句,*Count getter 方法在 Spock 2 中已弃用,但它们仍然有效。您可以轻松地用更新的替换它们,我只是想 post 代码 运行 在 Spock 版本 1.x 和 2.x.

中都没有变化

更新 2: 如果你想 运行 相同的测试,例如10x并发,每个都在自己的线程中,Groovy一个简单的方法是:

(1..10).collect { Thread.start { new EmbeddedSpecRunner().runClass(MyTest) } }*.join()

或者用一些换行符可能更容易阅读:

(1..10)
  .collect { 
    Thread.start { new EmbeddedSpecRunner().runClass(MyTest) }
  }
  *.join()

我假设您熟悉 collect (similar to map for Java streams) and the star-dot operator *.(对可迭代对象中的每个项目调用一个方法)。