Spock Mock不能进行单元测试

时间:2016-02-26 16:31:06

标签: groovy spock

我从Spock单元测试中得到了奇怪的结果,我认为是由于滥用Groovy的TupleConstructor注释引起的。但是,感谢另一位用户的帮助,我发现Spock创建模拟的方式存在问题。虽然我通过用实例替换注入的模拟来解决问题,但实际上我需要在这里工作。

我的主要课程:

@Canonical
@TupleConstructor(callSuper = true)
abstract class Vehicle {
    Long id
}

@Canonical
@TupleConstructor(callSuper = true, includeSuperProperties = true)
abstract class Foobaz extends Vehicle {
    String name
    String label
    String description
}

@Canonical
@TupleConstructor(callSuper = true, includeSuperProperties = true)
class Fizz extends Foobaz {
    // This is an empty class that creates a meaningful name over the
    // abstract Foobaz parent class. This may seem like bad design in
    // this analogy, but I assure you it makes sense (from a Domain-Driven
    // Design perspective) in my actual application.
}

@Canonical
@TupleConstructor(callSuper = true, includeSuperProperties = true)
class Car extends Vehicle {
    Fizz fizz1
    Fizz fizz2

    @Override
    String toString() {
        "${fizz1.name} - ${fizz2.name}"
    }
}

我的Spock测试:

class CarSpec extends Specification {
    def "toString() generates a correct string"() {
        given: "a Car with some mocked dependencies"
        String f1 = 'fizzy'
        String f2 = 'buzzy'
        Fizz fizz1 = Mock(Fizz)
        Fizz fizz2 = Mock(Fizz)

        fizz1.name >> f1
        fizz2.name >> f2

        Car car = new Car(1L, fizz1, fizz2)

        when: "we call toString()"
        String str = car.toString()

        then: "we get a correctly formatted string"
        "${f1} - ${f2}" == str
    }
}

但是当我运行这个时,我得到以下失败/错误:

Condition not satisfied:

"${f1} - ${f2}" == str
  |        |     |  |
  fizzy    buzzy |  null - null
                 false
                 <omitting details here for brevity>

Expected :null - null

Actual   :fizzy - buzzy

我出错的任何想法?

2 个答案:

答案 0 :(得分:3)

如果您将规格更改为:

class CarSpec extends Specification {
    def "toString() generates a correct string"() {
        given: "a Car with some mocked dependencies"
        String f1 = 'fizzy'
        String f2 = 'buzzy'
        Fizz fizz1 = Mock()
        Fizz fizz2 = Mock()

        Car car = new Car(1L, fizz1, fizz2)

        when: "we call toString()"
        String str = car.toString()

        then: "we get a correctly formatted string + getProperty('name') is called once on each Mock"
        "$f1 - $f2" == str

        1 * fizz1.getProperty('name') >> f1
        1 * fizz2.getProperty('name') >> f2
    }
}

所以你在then块中定义了交互,那么它应该都可以正常工作......

答案 1 :(得分:2)

从我们对@ smeeb的questions的另一个讨论开始,我对此进行了更多研究,因为我很困惑为什么这不起作用。

我创建了自己的测试。

class SomeTest extends Specification {

    static class Driver {

        String getName(Superclass superclass) {
            return superclass.name
        }
    }

    static abstract class Superclass {
        String name
    }

    static class Subclass extends Superclass {
    }


    def 'test'() {
        given:
        def driver = new Driver()
        def subclass = Mock(Subclass)

        subclass.name >> 'test'

        expect:
        driver.getName(subclass) == 'test'
    }
}

它失败了@smeeb看到的同样问题。

driver.getName(subclass) == 'test'
|      |       |         |
|      null    |         false
|              Mock for type 'Subclass' named 'subclass'

我尝试更改了一些不同的内容,发现当我从abstract移除Superclass修饰符或将return superclass.name更改为return superclass.getName()时,测试开始工作。< / p>

在使用自动生成的访问器从抽象超类获取继承的公共字段之间,Groovy级别上似乎存在一种奇怪的交互。

因此,在您的情况下,请从abstract删除FooBaz修饰符,或将代码更改为:

@Override
String toString() {
    "${fizz1.getName()} - ${fizz2.getName()}"
}