Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/386.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在单元测试中比较对象的正确方法_Java_Unit Testing_Grails_Junit - Fatal编程技术网

Java 在单元测试中比较对象的正确方法

Java 在单元测试中比较对象的正确方法,java,unit-testing,grails,junit,Java,Unit Testing,Grails,Junit,我正在为我的grails应用程序编写单元测试,我意识到我真的不知道如何正确地断言一个对象是否是正确的对象 例如,给定此测试: void testExampleTest() { mockSession.person = new Person(firstName:'John', lastName:'Doe', middleInitial:'E') def model = controller.testMethod() ...assertions... } 及 如何确保我添加

我正在为我的grails应用程序编写单元测试,我意识到我真的不知道如何正确地断言一个对象是否是正确的对象

例如,给定此测试:

void testExampleTest() {
    mockSession.person = new Person(firstName:'John', lastName:'Doe', middleInitial:'E')
    def model = controller.testMethod()
    ...assertions...
}

如何确保我添加到会话中的person对象在模型中正确传递?使用它是否足够

assertEquals( person,model['person'] )
或者因为我自己将对象注入会话,所以使用它是否更有意义

assertEquals( person.firstName, model['person'].firstName )
assertEquals( person.lastName, model['person'].lastName )
assertequals( person.middleName, model['person'].middleName )
在我看来,只要对象有一个正确定义的equals方法,第一种方法就足够了,但我只是想看看传统的方法是什么


谢谢

有趣的是,今天我和一位同事进行了类似的讨论。我们的结论是

比较费力的逐属性比较的一个优点是,它报告特定的差异,而不仅仅是“不,它们不相等”,这可能很方便

此外,我们对某些类没有控制权,其中一些类缺少equals方法


我们打算研究是否有可能使用反射来实现比较器,从而消除一些繁琐的工作。

如果正确定义了equals,那么您是对的。问题是,如果正确定义了equals(这意味着它的行为符合您的预期),您可能必须首先进行单元测试


如果为Person类创建一个模型,这可能会变得更加困难。在这种情况下,您不关心equals是否正常工作,因为您只想检查某些属性是否被正确设置/访问。这就是为什么我喜欢在可能和必要的情况下检查原语值。我发现它使测试更具描述性(尽管它可能变得非常冗长)。

正如您所写的,如果测试数据有一个合适的equals方法,您可以使用它。这里的“适当”表示它测试您想要测试的属性

我经常使用只比较其ID属性的数据库实体。对于这些对象,我需要分别测试每个属性,看看它们是否相等。我编写了一个小助手,它允许我为许多属性编写一个断言,如下所示:

assertEqualProperties(person, model['person'], "firstName", "lastName", "middleName");

这个helper方法使用反射来访问属性(不是直接调用commons bean库)。在Groovy中,肯定存在一种不需要显式反射的语法。该方法将第一个非相等属性报告为测试失败。

在Grails中,每个对象都是可序列化的,因此您可以使用它们的XML序列化来比较这两个对象:

public void compareXML(Object a, Object b)
    ByteArrayOutputStream aBaos = new ByteArrayOutputStream();
    XMLEncoder aEncoder = new XMLEncoder(aBaos);
    aEncoder.writeObject(a);
    aEncoder.close();
    String xmlA = baos.toString();

    ByteArrayOutputStream bBaos = new ByteArrayOutputStream();
    XMLEncoder bEncoder = new XMLEncoder(bBaos);
    bEncoder.writeObject(b);
    bEncoder.close();
    String xmlB = bBaos.toString();

    assertEquals(xmlA, xmlB);
}

如果您在eclipse中工作,您将获得两个XML字符串的良好文本比较,显示所有差异。

在这个特定实例中,测试单个属性只是您识别对象的特定实例的一种方法,它会模糊测试的意义。您特别关心并应该声明的是,
model['person']
与您最初作为
person
输入的对象完全相同:

assertSame(person, model['person'])
或者使用Hamcrest,它允许更具表现力的断言:

assertThat(model['person'], sameInstance(person))

我使用
assertSame()
。逐字段比较比必要的工作要多得多-您模拟了数据,因此只需声明模拟的值已正确返回。

我发现逐属性进行比较更可靠,并使您能够更精确地控制比较的方式,缺点是设置和维护

每个属性的比较需要在每个测试中重复,所以这是一个很好的旧代码复制。最好有一个合适的
equals()


当然,您可以在运行时添加一个实用方法
personEquals()
,甚至覆盖
Person.equals()
。对于mocked类,您可能不得不这样做。我个人坚持使用较短的代码,如果可能的话,只使用一个
assertEquals()

另请参见我的答案:commons beans库使基于反射的访问变得简单,可以用来构建多属性断言方法。事实上,如果被测试的对象预期会产生放入的相同实例,Grails的GUnit在开箱即用的对象差异的文本表示方面做得更好。
assertThat(model['person'], sameInstance(person))