Lar*_* KJ 4 groovy equality spock
如何使用spock检查深层对象是否相等.
假设我们有一个超级简单的测试,可以与相同的人物对象进行比较
def "A persons test"() {
setup:
def person1 = new Person("Foo", new Address("Bar"))
def person2 = new Person("Foo", new Address("Bar"))
expect:
person1 == person2
}
Run Code Online (Sandbox Code Playgroud)
测试失败
Condition not satisfied:
person1 == person2
| | |
| | Person@6bedbc4d
| false
Person@57af006c
Run Code Online (Sandbox Code Playgroud)
这看起来像是一种断言平等的非常自然的方式.
开始使用spock的主要原因之一是避免编写大量的hamcrest样板匹配器代码.
Spock没有用于执行深度对象比较的内置机制,因为定义对象相等性超出了任何测试框架的范围.你可以做各种各样的事情.
如果您的类(Person和Address)都是Groovy类,则可以使用两个类的注释生成equals和hashCode方法@EqualsAndHashCode,例如:
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
}
}
Run Code Online (Sandbox Code Playgroud)
这只是在Groovy中实现这两种方法的一种方便的替代方法.
如果要将两个对象与==运算符进行比较,则必须在两个类中定义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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
在此示例中,使用IntelliJ IDEA"Generate equals and hashCode"命令定义了两种方法.
如果你不想手动定义两种方法(例如因为你要记得随时改变他们修改您的类字段),那么你可以使用龙目岛的@EqualsAndHashCode注解,做类似Groovy的标注的东西,但可以适用于任何Java类.
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
}
}
Run Code Online (Sandbox Code Playgroud)您可以尝试使用第三方工具,如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
}
}
Run Code Online (Sandbox Code Playgroud)无论如何,我肯定会建议界定equals和hashCode以这种或那种方式和简单的使用==操作.希望能帮助到你.