如何使用闭包来捕获特定类型的调用并忽略其他类型?

时间:2014-12-08 08:34:36

标签: groovy closures spock

我有一个模拟方法可以接受抽象类型的所有子项。在测试中,这个方法可能被不同的子项多次调用,我想检查它是否被特定类型调用一次这样:

1*mockObject.method(_) {SpecificType ct->
     //check the ct's field value
}

问题是闭包始终捕获第一次调用,原因是:

mockObjectt.method(_)  

无法区分不同的子类型,因此它匹配所有调用,然后我尝试了另外一种方式:

 1*mockObject.method({it instanceof SpecificType}) {SpecificType ct->
     //check the ct's field value
} 

但这种方式的问题是:

 {SpecificType ct->
     //Here,any check will return true,
     //I think the checkings in here are ignored
 } 

总是被忽略(我想我在这里误用了groovy')

所以问题是:

 Is there elegant way to capture the invocation by specific child type with specific values and ignore others?

2 个答案:

答案 0 :(得分:2)

怎么样:1*mockObject.method({it instanceof SpecificType && it.field == fieldValue })

答案 1 :(得分:1)

看看这个示例代码:

import spock.lang.Specification

class SimpleTestSpec extends Specification {

    private static class A { }

    private static class B extends A { }

    private static class C extends B { }

    private static class D extends A { }

    private static class TestClass {
        String foo(A value) {
            return "A: ${value}"
        }

        String foo(B value) {
            return "B: ${value}"
        }

        String foo(C value) {
            return "C: ${value}"
        }

        String foo(D value) {
            return "D: ${value}"
        }
    }

    private static class ComponentClass {
        private final TestClass testClass

        ComponentClass(TestClass testClass) {
            this.testClass = testClass
        }

        String foo(A value) {
            return testClass.foo(value)
        }
    }

    TestClass testClassMock = Mock(TestClass)

    ComponentClass componentClass = new ComponentClass(testClassMock)

    def setup() {
        testClassMock.foo(_ as D) >> "DDD"
        testClassMock.foo(_ as C) >> "CCC"
        testClassMock.foo(_ as B) >> "BBB"
        testClassMock.foo(_ as A) >> "AAA"
    }

    def "should use mocked DDD result"() {
        when:
        String result = testClassMock.foo(new D())

        then:
        result == "DDD"
    }

    def "should use mocked CCC result"() {
        when:
        String result = testClassMock.foo(new C())

        then:
        result == "CCC"
    }

    def "should use mocked BBB result"() {
        when:
        String result = testClassMock.foo(new B())

        then:
        result == "BBB"
    }

    def "should use mocked AAA result"() {
        when:
        String result = testClassMock.foo(new A())

        then:
        result == "AAA"
    }

    def "should record invocation based on dynamic type"() {
        when:
        componentClass.foo(new C())

        then:
        1 * testClassMock.foo(_ as C)
    }

    def "should return result associated with mocked invocation in runtime"() {
        when:
        String result = componentClass.foo(new D())

        then:
        result == "DDD"
    }
}

Gist文件:https://gist.github.com/wololock/c59151b67d4c9b0c0c8e

您可以使用as强制转换运算符指定参数的预期类型。但是有一个棘手的部分 - 您需要按特定顺序存根类行为:从最具体到最一般。尝试混合setup()中的顺序,然后您将看到测试将开始失败。

您还可以使用Groovy的动态方法调用 - 注意ComponentClass如何使用之前存在预期行为的injectest TestClass实例。即使通过最常规的类型方法进行外部调用,您也可以计算与特定类型相关的调用次数。

我希望它可以帮助您解决问题。最好!