当使用并行流时,Spock单元测试被卡住

时间:2015-10-21 16:02:48

标签: multithreading unit-testing java-8 spock

我在Spock单元测试中对Java 8并行流有一种奇怪的行为。

以下代码采用PlanConfigConstraintValidator列表并验证是否全部返回true

Spock中此代码的单元测试如下。在我添加.parallel()之前,一切正常。当使用并行流时,单元测试卡住并且永不停止。

如果我只返回一个Mock(PlanConfigConstraintValidator),它会起作用,但当大小超过一个时,则不行。

我也在底部提供了线程转储。

@Override
public boolean isValid(PlanConfig planConfig, ConstraintValidatorContext context) {
    return getPlanConfigConstraintValidators().stream().parallel()
            .filter(validator -> shouldValidate(planConfig, validator))
            .allMatch(validator -> isValid(planConfig, context, validator));
}

这是单元测试代码

def "isValid - all validators return true"() {
    when:
    def validator = Spy(PlanConfigValidator) {
        getPlanConfigConstraintValidators() >> [
                Mock(PlanConfigConstraintValidator),
                Mock(PlanConfigConstraintValidator),
        ]
        shouldValidate(_, _) >> true
        isValid(_, _, _) >> true
    }
    def result = validator.isValid(new PlanConfig(), Mock(ConstraintValidatorContext))

    then:
    result
}

线程转储

"main" #1 prio=5 os_prio=0 tid=0x00000000026aa000 nid=0x1dd78 in Object.wait() [0x00000000034ac000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000076da712d8> (a java.util.stream.MatchOps$MatchTask)
    at java.util.concurrent.ForkJoinTask.externalAwaitDone(ForkJoinTask.java:334)
    - locked <0x000000076da712d8> (a java.util.stream.MatchOps$MatchTask)
    at java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:405)
    at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:734)
    at java.util.stream.MatchOps$MatchOp.evaluateParallel(MatchOps.java:242)
    at java.util.stream.MatchOps$MatchOp.evaluateParallel(MatchOps.java:196)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
    at java.util.stream.ReferencePipeline.allMatch(ReferencePipeline.java:454)

Thread Dump

2 个答案:

答案 0 :(得分:0)

我只是遇到了类似的问题,并且能够通过以下方法解决它:

  1. 使用parallelStream()而不是stream()。parallel()
  2. 这样的实现列表(在Groovy中):
    private class NoParallelStreamsList implements List {

        @Delegate
        List delegateList

        @Override
        Stream parallelStream() {
            delegateList.stream()
        }
    }

因此在OP的示例中,他们将getPlanConfigConstraintValidators的模拟更改为如下所示:

        getPlanConfigConstraintValidators() >> new NoParallelStreamsList(
                delegateList: [
                    Mock(PlanConfigConstraintValidator),
                    Mock(PlanConfigConstraintValidator),
                ]
        )

答案 1 :(得分:0)

我今天有一个类似的问题,并且似乎该问题与Spock中LiveData的实现有关。

在我的情况下,使用Spy不能解决问题。

对我来说,讨论here很有帮助。

我最终得到了一个匿名子类。我的解决方案的OP示例如下所示:

parallelStream()