Spock没有内置机制来执行深度对象比较,因为定义对象相等性超出了任何测试框架的范围。您可以做很多事情。
1. 两个类都是 Groovy 类
如果您的类(Person
和 Address
)都是 Groovy 类,您可以对这两个类使用 @EqualsAndHashCode
注解生成 equals
和 hashCode
方法,例如:
import groovy.transform.EqualsAndHashCode
import groovy.transform.TupleConstructor
import spock.lang.Specification
class PersonSpec extends Specification {
def "a person test"() {
setup:
def person1 = new Person("Foo", new Address("Bar"))
def person2 = new Person("Foo", new Address("Bar"))
expect:
person1 == person2
}
@TupleConstructor
@EqualsAndHashCode
static class Person {
String name
Address address
}
@TupleConstructor
@EqualsAndHashCode
static class Address {
String city
}
}
这只是在Groovy中同时实现两种方法的方便替代方法。
2. 这两个类都是Java类
如果你想使用==
运算符比较这两个对象,那么你需要在这两个类中定义equals
和hashCode
方法,例如:
public final class Person {
private final String name;
private final Address address;
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public Address getAddress() {
return address;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (name != null ? !name.equals(person.name) : person.name != null) return false;
return address != null ? address.equals(person.address) : person.address == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (address != null ? address.hashCode() : 0);
return result;
}
static class Address {
private final String city;
public Address(String city) {
this.city = city;
}
public String getCity() {
return city;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Address address = (Address) o;
return city != null ? city.equals(address.city) : address.city == null;
}
@Override
public int hashCode() {
return city != null ? city.hashCode() : 0;
}
}
}
在这个例子中,两种方法都是使用IntelliJ IDEA的“生成equals和hashCode”命令定义的。
3. 我可以使用Lombok!
如果你不想手动定义这两个方法(比如因为你必须记得在修改类字段时更改它们),那么你可以使用Lombok的@EqualsAndHashCode
注解来执行类似于Groovy注解的操作,但可应用于任何Java类。
4. 我想保留默认的equals
和hashCode
方法
好吧,在这种情况下,你可以尝试各种方法:
你可以像这样逐个字段地比较两个对象:
class PersonSpec extends Specification {
def "a person test"() {
setup:
def person1 = new Person("Foo", new Address("Bar"))
def person2 = new Person("Foo", new Address("Bar"))
expect:
person1.name == person2.name
and:
person1.address.city == person2.address.city
}
@TupleConstructor
static class Person {
String name
Address address
}
@TupleConstructor
static class Address {
String city
}
}
您可以尝试使用第三方工具,例如Unitils反射断言
这可能听起来很奇怪,但您可以比较两个对象的JSON表示形式,类似于:
import groovy.json.JsonOutput
import groovy.transform.TupleConstructor
import spock.lang.Specification
class PersonSpec extends Specification {
def "a person test"() {
setup:
def person1 = new Person("Foo", new Address("Bar"))
def person2 = new Person("Foo", new Address("Bar"))
expect:
new JsonOutput().toJson(person1) == new JsonOutput().toJson(person2)
}
@TupleConstructor
static class Person {
String name
Address address
}
@TupleConstructor
static class Address {
String city
}
}
无论如何,我强烈建议以某种方式定义equals
和hashCode
,并简单地使用==
运算符。希望能够帮到你。
无论如何,我强烈建议以某种方式定义equals
和hashCode
,并简单地使用==
运算符。希望能够帮到你。
@Canonical
,而不是@EqualsAndHashCode
+@TupleConstructor
,以及这些数据类中也应该有的重要的@ToString
。 - Renatowith
来使测试更加简洁。http://spockframework.org/spock/docs/1.1/all_in_one.html#specs-as-doc - tim_yates