如何判断 Spock 是否真的在并行执行测试
How to tell if Spock is actually executing tests in parallel
我们有一些 API 集成测试需要大约 30 分钟才能 运行 测试 class where:
table 中有 19 行。我们正在尝试使用 Spock 的(实验性)Parellel Execution 功能来加快速度。我们正在使用一个简单的 SpockConfig.groovy
文件:
runner {
parallel {
enabled true
fixed(4)
}
}
在 GitLab 运行ner 上这仍然需要大约 30 分钟。有什么方法可以注销某些内容,以便我们可以验证测试是否 运行 并行进行?还是我误解了 Spock 并行化的本质?
您可以在多个级别上并行执行 Spock 测试,即每个规范(测试 class)或每个功能(测试方法)。 per-method 设置还意味着在迭代(展开)测试中,迭代可以 运行 并行。这里有一些证据:
import static org.spockframework.runtime.model.parallel.ExecutionMode.CONCURRENT
runner {
parallel {
enabled true
// These values are the default already, specifying them is redundant
// defaultSpecificationExecutionMode = CONCURRENT
// defaultExecutionMode = CONCURRENT
fixed 4
}
}
package de.scrum_master.testing
import spock.lang.Specification
import static java.lang.System.currentTimeMillis
import static java.lang.Thread.currentThread
class ParallelExecutionTest extends Specification {
static long startTime = currentTimeMillis()
static volatile int execCount = 0
def "feature-A-#count"() {
given:
def i = ++execCount
printf "%5d %2d [%s] >> %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName
sleep 1000
printf "%5d %2d [%s] << %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName
where:
count << (1..8)
}
def "feature-B-#count"() {
given:
def i = ++execCount
printf "%5d %2d [%s] >> %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName
sleep 1000
printf "%5d %2d [%s] << %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName
where:
count << (1..8)
}
}
输出看起来像这样(我使用 volatile 变量是为了更容易地将编辑器中的日志输出分类为线程组 运行同时以 4 个为一组:
68 1 [ForkJoinPool-1-worker-3] >> feature-B-1
68 2 [ForkJoinPool-1-worker-2] >> feature-A-5
68 3 [ForkJoinPool-1-worker-1] >> feature-B-6
68 4 [ForkJoinPool-1-worker-4] >> feature-B-2
1177 1 [ForkJoinPool-1-worker-3] << feature-B-1
1177 3 [ForkJoinPool-1-worker-1] << feature-B-6
1179 4 [ForkJoinPool-1-worker-4] << feature-B-2
1180 2 [ForkJoinPool-1-worker-2] << feature-A-5
1191 5 [ForkJoinPool-1-worker-3] >> feature-B-3
1199 6 [ForkJoinPool-1-worker-4] >> feature-B-4
1200 7 [ForkJoinPool-1-worker-1] >> feature-B-5
1204 8 [ForkJoinPool-1-worker-2] >> feature-A-6
2199 5 [ForkJoinPool-1-worker-3] << feature-B-3
2205 7 [ForkJoinPool-1-worker-1] << feature-B-5
2213 6 [ForkJoinPool-1-worker-4] << feature-B-4
2213 8 [ForkJoinPool-1-worker-2] << feature-A-6
2203 9 [ForkJoinPool-1-worker-3] >> feature-B-7
2207 10 [ForkJoinPool-1-worker-1] >> feature-A-1
2217 11 [ForkJoinPool-1-worker-4] >> feature-B-8
2222 12 [ForkJoinPool-1-worker-2] >> feature-A-8
3205 9 [ForkJoinPool-1-worker-3] << feature-B-7
3213 10 [ForkJoinPool-1-worker-1] << feature-A-1
3229 12 [ForkJoinPool-1-worker-2] << feature-A-8
3230 11 [ForkJoinPool-1-worker-4] << feature-B-8
3208 13 [ForkJoinPool-1-worker-3] >> feature-A-2
3216 14 [ForkJoinPool-1-worker-1] >> feature-A-3
3234 15 [ForkJoinPool-1-worker-4] >> feature-A-4
3237 16 [ForkJoinPool-1-worker-2] >> feature-A-7
4214 13 [ForkJoinPool-1-worker-3] << feature-A-2
4230 14 [ForkJoinPool-1-worker-1] << feature-A-3
4245 15 [ForkJoinPool-1-worker-4] << feature-A-4
4245 16 [ForkJoinPool-1-worker-2] << feature-A-7
正如您可以清楚地看到的那样,通过您自己的设置,您可以预期规范中的多个功能甚至多个迭代 运行 同时进行。如果在您的情况下,并发迭代花费的时间与 运行 按顺序完成测试一样长,则可能意味着这些测试花费大量时间使用同步的共享资源或只能以其他方式使用同时由一个来电者。所以问题可能不是 Spock,而是共享资源或您同步的方式。
我们有一些 API 集成测试需要大约 30 分钟才能 运行 测试 class where:
table 中有 19 行。我们正在尝试使用 Spock 的(实验性)Parellel Execution 功能来加快速度。我们正在使用一个简单的 SpockConfig.groovy
文件:
runner {
parallel {
enabled true
fixed(4)
}
}
在 GitLab 运行ner 上这仍然需要大约 30 分钟。有什么方法可以注销某些内容,以便我们可以验证测试是否 运行 并行进行?还是我误解了 Spock 并行化的本质?
您可以在多个级别上并行执行 Spock 测试,即每个规范(测试 class)或每个功能(测试方法)。 per-method 设置还意味着在迭代(展开)测试中,迭代可以 运行 并行。这里有一些证据:
import static org.spockframework.runtime.model.parallel.ExecutionMode.CONCURRENT
runner {
parallel {
enabled true
// These values are the default already, specifying them is redundant
// defaultSpecificationExecutionMode = CONCURRENT
// defaultExecutionMode = CONCURRENT
fixed 4
}
}
package de.scrum_master.testing
import spock.lang.Specification
import static java.lang.System.currentTimeMillis
import static java.lang.Thread.currentThread
class ParallelExecutionTest extends Specification {
static long startTime = currentTimeMillis()
static volatile int execCount = 0
def "feature-A-#count"() {
given:
def i = ++execCount
printf "%5d %2d [%s] >> %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName
sleep 1000
printf "%5d %2d [%s] << %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName
where:
count << (1..8)
}
def "feature-B-#count"() {
given:
def i = ++execCount
printf "%5d %2d [%s] >> %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName
sleep 1000
printf "%5d %2d [%s] << %s%n", currentTimeMillis() - startTime, i, currentThread().name, specificationContext.currentIteration.displayName
where:
count << (1..8)
}
}
输出看起来像这样(我使用 volatile 变量是为了更容易地将编辑器中的日志输出分类为线程组 运行同时以 4 个为一组:
68 1 [ForkJoinPool-1-worker-3] >> feature-B-1
68 2 [ForkJoinPool-1-worker-2] >> feature-A-5
68 3 [ForkJoinPool-1-worker-1] >> feature-B-6
68 4 [ForkJoinPool-1-worker-4] >> feature-B-2
1177 1 [ForkJoinPool-1-worker-3] << feature-B-1
1177 3 [ForkJoinPool-1-worker-1] << feature-B-6
1179 4 [ForkJoinPool-1-worker-4] << feature-B-2
1180 2 [ForkJoinPool-1-worker-2] << feature-A-5
1191 5 [ForkJoinPool-1-worker-3] >> feature-B-3
1199 6 [ForkJoinPool-1-worker-4] >> feature-B-4
1200 7 [ForkJoinPool-1-worker-1] >> feature-B-5
1204 8 [ForkJoinPool-1-worker-2] >> feature-A-6
2199 5 [ForkJoinPool-1-worker-3] << feature-B-3
2205 7 [ForkJoinPool-1-worker-1] << feature-B-5
2213 6 [ForkJoinPool-1-worker-4] << feature-B-4
2213 8 [ForkJoinPool-1-worker-2] << feature-A-6
2203 9 [ForkJoinPool-1-worker-3] >> feature-B-7
2207 10 [ForkJoinPool-1-worker-1] >> feature-A-1
2217 11 [ForkJoinPool-1-worker-4] >> feature-B-8
2222 12 [ForkJoinPool-1-worker-2] >> feature-A-8
3205 9 [ForkJoinPool-1-worker-3] << feature-B-7
3213 10 [ForkJoinPool-1-worker-1] << feature-A-1
3229 12 [ForkJoinPool-1-worker-2] << feature-A-8
3230 11 [ForkJoinPool-1-worker-4] << feature-B-8
3208 13 [ForkJoinPool-1-worker-3] >> feature-A-2
3216 14 [ForkJoinPool-1-worker-1] >> feature-A-3
3234 15 [ForkJoinPool-1-worker-4] >> feature-A-4
3237 16 [ForkJoinPool-1-worker-2] >> feature-A-7
4214 13 [ForkJoinPool-1-worker-3] << feature-A-2
4230 14 [ForkJoinPool-1-worker-1] << feature-A-3
4245 15 [ForkJoinPool-1-worker-4] << feature-A-4
4245 16 [ForkJoinPool-1-worker-2] << feature-A-7
正如您可以清楚地看到的那样,通过您自己的设置,您可以预期规范中的多个功能甚至多个迭代 运行 同时进行。如果在您的情况下,并发迭代花费的时间与 运行 按顺序完成测试一样长,则可能意味着这些测试花费大量时间使用同步的共享资源或只能以其他方式使用同时由一个来电者。所以问题可能不是 Spock,而是共享资源或您同步的方式。