ProgramingTip

한 단위가 hashCode-equals 계약을 어떻게 테스트해야합니까?

bestdevel 2020. 10. 27. 23:00
반응형

한 단위가 hashCode-equals 계약을 어떻게 테스트해야합니까?


요컨대, Java의 object.hashCode ()에 따른 hashCode 계약 :

  1. 동일 함 ()에 영향을주지 않는 것이 변경되지 않습니다.
  2. 같음 ()은 해시 코드가 ==임을 의미합니다.

주로 변경 불가능한 데이터에서 관심이 가정 해 봅시다. 해당 정보는 생성되지 않습니다. 그것은 # 2를 남깁니다. ==를 의미한다는 것을 확인하는 것입니다.

분명히 우리는 그 집합이 사소하게 작지 않는 한 모든 상상할 수있는 데이터 개체를 테스트 할 수 없습니다. 일반적인 경우를 포함 할 수있는 단위 테스트를 작성하는 가장 좋은 방법은 무엇입니까?

이 클래스의 인스턴스는 변경 불가능한 클래스의 인스턴스를 생성하는 방법을 생성합니다. 이 단위 테스트는 모든 것을 다루어야합니다. 내 머리 생성자에서 진입 점은 생성자, 역 생성자입니다 (생성자 호출 문제를 수 있어야 함).

[연구를 통해 내 질문에 답하려고 노력할 것입니다. 다른 StackOverflowers의 입력은이 프로세스에 대한 환영받는 안전입니다.]

[다른 OO 언어에도 적용 할 수 있으므로 태그를 추가하겠습니다.]


EqualsVerifier 는 계약을 테스트하는 데이며 동일합니다. GSBase의 EqualsTester 에는 문제 가 없습니다 . 나는 그것을 확실히 추천 할 것입니다.


내 조언은 이것이 사실이 아닌 이유 / 방법을 생각한 다음 상황을 대상으로하는 단위 테스트를 작성하는 것입니다.

예를 들어 사용자 지정 Set클래스 가 존재 가정 해 보겠습니다 . 두 세트가 동일한 요소를 포함하는 경우 동일하지만 두 세트의 기본 데이터 구조는 해당 요소가 다른 순서로 저장되는 경우 다를 수 있습니다. 예를 들면 :

MySet s1 = new MySet( new String[]{"Hello", "World"} );
MySet s2 = new MySet( new String[]{"World", "Hello"} );
assertEquals(s1, s2);
assertTrue( s1.hashCode()==s2.hashCode() );

이 경우 구현 한 해싱 알고리즘에 따라 세트의 요소 순서가 해시에 영향을 미칠 수 있습니다. 그래서 이것은 제가 말하는 테스트의 종류입니다. 왜냐하면 그것은 두 가지 경우에서 발생하는 것과 동일하다는 것입니다.

어떤 것이 든 자신의 사용자 정의 클래스와 권장 표준을 사용합니다.


이를 위해 junit 애드온을 사용할 가치가 있습니다. EqualsHashCodeTestCase http://junit-addons.sourceforge.net/ 클래스를 확인하십시오. 관리자 확장 및 createInstance 및 createNotEqualInstance를 구현할 수 있습니다. 그러면 hashCode 메소드가 올바른지 확인합니다.


GSBase EqualsTester 를 추천 합니다 . 기본적으로 원하는 것을 수행합니다. 그래도 두 가지 (사소한) 문제가 있습니다.

  • 생성자는 모든 작업을 수행하기 좋은 방법이라고 생각하지 않습니다.
  • 클래스 A의 인스턴스가 클래스 A의 하위 클래스의 인스턴스와 같으면 실패합니다. 이것은 반드시 같음 계약을 위반하는 것은 아닙니다.

[이 글을 쓰는 시점에 다른 세 개의 답변이 게시되었습니다.]

다시 말해서, 내 질문의 목적은 표준 테스트 사례를 찾아서 서로 동의 hashCode하고 있는지 확인하는 것 equals입니다. 이 질문에 대한 나의 접근 방식은 문제의 클래스, 즉 불변 데이터를 사용할 때 프로그래머가 취하는 경로입니다. 예를 들면 :

  1. equals()작성하지 않고 hashCode(). 이것은 종종 두 인스턴스의 필드가 동등 함을 의미하는 동등성이 정의 의미합니다.
  2. hashCode()작성하지 않고 equals(). 이 프로그래머가보다 효율적인 해싱 알고리즘을 찾고 있음을 의미 할 수 있습니다.

# 2의 경우 문제가없는 것입니다. 추가 인스턴스가 만들어 equals()지지 않을까요? 최악의 경우 해시 알고리즘은 질문의 범위를 벗어난 해시 맵의 성능을 사용할 수 있습니다.

# 1의 경우 표준 단위 테스트는 생성자에 전달 된 동일한 데이터를 사용하여 동일한 개체의 두 인스턴스를 동일한 해시 코드를 확인하는 작업을 수반합니다. 오탐은 어떻습니까? 그럼에도 불구하고 건전하지 않은 알고리즘에서 동일한 해시 코드를 생성하는 생성자 변수를 선택할 수 있습니다. 우선 순위 변수를 피하는 경향이있는 정신을 나열하는 것입니다. 여기서 길은 소스 코드를 검사하고 equals(), 열심히 생각하고,이를 기반으로 테스트를 작성하는 것이지만, 경우에 따라 필요한 수있는 문제를 신속하게 테스트 할 수 있습니다. 이 질문의.

예를 들어 테스트 할 클래스 (Data라고 함)에 문자열을 사용하는 생성자와. 인 인스턴스가 생성 된 문자열에서 equals()생성 된 인스턴스가 equals()있는 경우 좋은 테스트는 다음을 테스트 할 것입니다.

  • new Data("foo")
  • 다른 new Data("foo")

내 생각에 올바른 결과를 더 많은 new Data(new String("foo"))보다 올바른 해시를 할 가능성이 더 높지만, 해시 코드를 확인하여 String이 인턴 코드가 없어도 Data.equals()됩니다.

Eli Courtwright 의 대답은 equals사양 에 대한 지식을 기반으로 해시 알고리즘을 깨는 방법을 열심히 생각하는 예입니다 . 특수 컬렉션의 예는 사용자가 만든 Collections가 표시되고 해시 알고리즘에서 엉망이 경향 이 있으므로 좋은 컬렉션입니다 .


이 테스트에서 여러 개의 어설 션이있는 유일한 경우 중 하나입니다. 메소드를 테스트해야 할 때 hashCode 메소드를 확인해야합니다. 따라서 각 메소드는 메소드 테스트 케이스에서 hashCode 계약도 확인하십시오.

A one = new A(...);
A two = new A(...);
assertEquals("These should be equal", one, two);
int oneCode = one.hashCode();
assertEquals("HashCodes should be equal", oneCode, two.hashCode());
assertEquals("HashCode should not change", oneCode, one.hashCode());

물론 좋은 hashCode를 확인하는 것은 또 다른 연습입니다. 솔직히 저는 hashCode가 동일한 실행에서 변경되지 않았는지 확인하기 위해 이중 검사를 수행하지 않을 것입니다. 더 잘 처리되는 문제는 코드에서 해결되고 개발자가 좋은 방법이 아닌지 이해하도록 도와 줌. hashCode 메서드를 작성합니다.


http://code.google.com/p/guava-libraries/source/browse/guava-testlib/src/com/google/common/testing/EqualsTester.java 와 사용하는 것을 하여 equals 및 hashCode를 테스트 할 수도 있습니다. .


클래스가 있으면 Thing대부분의 다른 클래스 처럼 ThingTest해당 클래스에 대한 모든 단위 테스트를 보유 하는 클래스를 작성합니다 . 각각 ThingTest방법이 있습니다

 public static void checkInvariants(final Thing thing) {
    ...
 }

경우 Thing클래스 재정의 해시 코드가 동일하고는 방법이있다

 public static void checkInvariants(final Thing thing1, Thing thing2) {
    ObjectTest.checkInvariants(thing1, thing2);
    ... invariants that are specific to Thing
 }

이 메서드는 개체 쌍 사이에 유지되도록 설계된 모든 불변성 을 확인 Thing합니다. ObjectTest객체의 쌍 사이에 유지해야하는 모든 불변을 확인하기위한 책임에 방법을 위임합니다. 마찬가지로 equals그리고 hashCode모든 객체 방법, 그 방법이 확인되어 hashCodeequals일치한다.

그런 다음 Thing개체 쌍을 생성 하고이를 pairwise checkInvariants메서드에 전달하는 몇 가지 테스트 메서드가 있습니다 . 등가 분할을 사용하여 테스트 할 가치가있는 쌍을 결정합니다. 일반적으로 각 쌍을 하나의 속성에서만 다르게 만들고 두 개의 동등한 객체를 테스트하는 테스트를 만듭니다.

나는 또한 때때로 3 개의 인수 checkInvariants방법을 가지고 있지만 그것이 findinf 결함에서 덜 유용하다는 것을 알게 되었기 때문에 이것을 자주하지 않습니다.

참고 URL : https://stackoverflow.com/questions/188311/how-should-one-unit-test-the-hashcode-equals-contract

반응형