Spock Mock 不适用于单元测试
Spock Mock not working for unit test
我从 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
}
}
但是当我 运行 这个我得到以下 failure/error:
Condition not satisfied:
"${f1} - ${f2}" == str
| | | |
fizzy buzzy | null - null
false
<omitting details here for brevity>
Expected :null - null
Actual :fizzy - buzzy
知道我哪里出错了吗?
如果您将规范更改为:
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
块中定义了交互,那么它应该一切正常......
根据我们对@smeeb 的另一个 的讨论,我对此进行了更多研究,因为我很困惑为什么这不起作用。
我创建了自己的测试。
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'
我尝试更改一些不同的东西,发现当我从 Superclass
中删除 abstract
修饰符或将 return superclass.name
更改为 return superclass.getName()
时,测试开始工作.
使用自动生成的访问器从抽象超类继承 public 字段之间似乎在 Groovy 级别上存在奇怪的交互。
因此,在您的情况下,要么从 FooBaz
中删除 abstract
修饰符,要么将您的代码更改为:
@Override
String toString() {
"${fizz1.getName()} - ${fizz2.getName()}"
}
我从 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
}
}
但是当我 运行 这个我得到以下 failure/error:
Condition not satisfied:
"${f1} - ${f2}" == str
| | | |
fizzy buzzy | null - null
false
<omitting details here for brevity>
Expected :null - null
Actual :fizzy - buzzy
知道我哪里出错了吗?
如果您将规范更改为:
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
块中定义了交互,那么它应该一切正常......
根据我们对@smeeb 的另一个
我创建了自己的测试。
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'
我尝试更改一些不同的东西,发现当我从 Superclass
中删除 abstract
修饰符或将 return superclass.name
更改为 return superclass.getName()
时,测试开始工作.
使用自动生成的访问器从抽象超类继承 public 字段之间似乎在 Groovy 级别上存在奇怪的交互。
因此,在您的情况下,要么从 FooBaz
中删除 abstract
修饰符,要么将您的代码更改为:
@Override
String toString() {
"${fizz1.getName()} - ${fizz2.getName()}"
}