소스가없는 equals () 메서드가없는 클래스가 있다고 가정 해 보겠습니다. 해당 클래스의 두 인스턴스에 대해 동등성을 주장하고 싶습니다.
여러 단언을 할 수 있습니다.
assertEquals(obj1.getFieldA(), obj2.getFieldA());
assertEquals(obj1.getFieldB(), obj2.getFieldB());
assertEquals(obj1.getFieldC(), obj2.getFieldC());
...
초기 주장이 실패하면 완전한 평등 그림을 얻지 못하기 때문에이 솔루션이 마음에 들지 않습니다.
수동으로 직접 비교하고 결과를 추적 할 수 있습니다.
String errorStr = "";
if(!obj1.getFieldA().equals(obj2.getFieldA())) {
errorStr += "expected: " + obj1.getFieldA() + ", actual: " + obj2.getFieldA() + "\n";
}
if(!obj1.getFieldB().equals(obj2.getFieldB())) {
errorStr += "expected: " + obj1.getFieldB() + ", actual: " + obj2.getFieldB() + "\n";
}
...
assertEquals("", errorStr);
이것은 나에게 완전한 평등 그림을 제공하지만 투박합니다 (그리고 가능한 null 문제에 대해서도 설명하지 않았습니다). 세 번째 옵션은 Comparator를 사용하는 것이지만 compareTo ()는 어떤 필드가 동일하지 않은지 알려주지 않습니다.
하위 클래스를 지정하고 같음 (ugh)을 재정의하지 않고 객체에서 원하는 것을 얻는 더 나은 방법이 있습니까?
답변
최신 버전의 Mockito 사용 :
Assert.assertTrue(new ReflectionEquals(expected, excludeFields).matches(actual));
이전 버전의 경우 다음을 사용하십시오.
Assert.assertThat(actual, new ReflectionEquals(expected, excludeFields));
답변
여기에 많은 정답이 있지만 내 버전도 추가하고 싶습니다. 이것은 Assertj를 기반으로합니다.
import static org.assertj.core.api.Assertions.assertThat;
public class TestClass {
public void test() {
// do the actual test
assertThat(actualObject)
.isEqualToComparingFieldByFieldRecursively(expectedObject);
}
}
업데이트 : assertj v3.13.2에서이 메서드는 Woodz가 주석에서 지적한 것처럼 더 이상 사용되지 않습니다. 현재 권장 사항은
public class TestClass {
public void test() {
// do the actual test
assertThat(actualObject)
.usingRecursiveComparison()
.isEqualTo(expectedObject);
}
}
답변
저는 일반적으로 org.apache.commons.lang3.builder.EqualsBuilder를 사용하여이 사용 사례를 구현합니다.
Assert.assertTrue(EqualsBuilder.reflectionEquals(expected,actual));
답변
조금 오래되었다는 것을 알고 있지만 도움이 되었으면합니다.
나는 당신과 똑같은 문제에 부딪 혔기 때문에 조사 끝에 이것과 비슷한 질문을 거의 발견하지 못했고, 해결책을 찾은 후에 나는 다른 사람들을 도울 수 있다고 생각했기 때문에 그 질문에 똑같이 대답했습니다.
이 유사한 질문에 대해 가장 많이 득표 한 답변 (저자가 선택한 답변이 아님)이 가장 적합한 솔루션입니다.
기본적으로 Unitils 라는 라이브러리를 사용하여 구성됩니다 .
이것이 사용입니다.
User user1 = new User(1, "John", "Doe");
User user2 = new User(1, "John", "Doe");
assertReflectionEquals(user1, user2);
클래스 User
가 구현하지 않아도 통과 합니다 equals()
. 더 많은 예제와 assertLenientEquals
그들의 튜토리얼 에서 호출되는 정말 멋진 어설 션을 볼 수 있습니다 .
답변
Apache commons lang ReflectionToStringBuilder를 사용할 수 있습니다.
테스트 할 속성을 하나씩 지정하거나 원하지 않는 속성을 제외하는 것이 좋습니다.
String s = new ReflectionToStringBuilder(o, ToStringStyle.SHORT_PREFIX_STYLE)
.setExcludeFieldNames(new String[] { "foo", "bar" }).toString()
그런 다음 두 문자열을 정상적으로 비교합니다. 반사가 느리다는 점에 대해서는 이것이 테스트 용이라고 가정하므로 그렇게 중요하지 않아야합니다.
답변
어설 션 (assertThat)에 hamcrest를 사용하고 있고 추가 테스트 라이브러리를 가져 오지 않으려면을 사용 SamePropertyValuesAs.samePropertyValuesAs
하여 재정의 된 equals 메서드가없는 항목을 어설 션 할 수 있습니다 .
장점은 또 다른 테스트 프레임 워크를 가져올 필요가 없으며 . 같은 것을 사용하는 expected: field=<value> but was field=<something else>
대신 assert가 실패 할 때 ( ) 유용한 오류를 제공 expected: true but was false
한다는 것 EqualsBuilder.reflectionEquals()
입니다.
단점은 얕은 비교이고 필드를 제외 할 수있는 옵션이 없기 때문에 (EqualsBuilder에있는 것처럼) 중첩 된 개체를 해결해야합니다 (예 : 개체를 제거하고 독립적으로 비교).
최상의 사례 :
import static org.hamcrest.beans.SamePropertyValuesAs.samePropertyValuesAs;
...
assertThat(actual, is(samePropertyValuesAs(expected)));
추악한 경우 :
import static org.hamcrest.beans.SamePropertyValuesAs.samePropertyValuesAs;
...
SomeClass expected = buildExpected();
SomeClass actual = sut.doSomething();
assertThat(actual.getSubObject(), is(samePropertyValuesAs(expected.getSubObject())));
expected.setSubObject(null);
actual.setSubObject(null);
assertThat(actual, is(samePropertyValuesAs(expected)));
그러니 독을 선택하십시오. 추가 프레임 워크 (예 : Unitils), 도움이되지 않는 오류 (예 : EqualsBuilder) 또는 얕은 비교 (hamcrest).
답변
라이브러리 Hamcrest 1.3 Utility Matchers 에는 같음 대신 반사를 사용하는 특수 매 처가 있습니다.
assertThat(obj1, reflectEquals(obj2));