2017-02-22 4 views
3

テスト目的でのみequals()hashCode()を定義することはコードの匂いと考えられているので、ユニットテストを行っている間にオブジェクトを比較するのにReflectionEqualsまたはカスタムマッチャーを使用することをお勧めします。equals()とhashCode()を定義せずにカスタムクラスのリストを比較するにはどうすればよいですか?

しかし、ReflectionEqualsやカスタムマッチャーをユーザー定義クラスのリストの比較に使用する方法はわかりません。

例えば、equals()hashCode()ReflectionEqualsまたはカスタムマッチャーのみ使用)を定義せずに次のコードをアサートするにはどうすればよいですか?

// When 
List<Record> actual = sut.findBySomeId(); 

// Then 
List<Record> expected = asList(
    aRecord()...build(), 
    aRecord()...build() 
); 
assertThat(expected, /* how to compare? */); 

答えて

1

私はequals/hashCodeをチェックするためにリフレクションを使用すること自体に別のコードの臭いであると言うでしょう。 Matcher

、あなたは(私が代わりにimportを使用し、明確にするための完全修飾名を使用)そのようなことを行う必要があります。これはresultvalueexpectedからのものと同じであることを確認します。必要なだけ多くのフィールドを追加できます。

assertThat(result, new org.hamcrest.BaseMatcher<MyObject>() { 
    public boolean matches(MyObject o) { 
    return java.lang.Objects.equals(o.getValue(), expected.getValue()); 
    } 
}); 

あなたは(何がグァバと、彼らは@VisibleForTestingと、このようなフィールドに注釈を付けないこと)、デフォルトの可視性を使用し、その後、あなたのクラスのフィールドのgetterを作成しない場合。

また、AssertJを見て、カスタムと流暢なマッチャーを作成することもできます(多かれ少なかれ同じように動作します)。

2

Hamcrestライブラリには、コレクションタイプのアサーションを作成するための豊富なマッチャが用意されています。特にhasItemhasItemscontainscontainsAnyOrderのようなマッチャーは、マッチャー自体を使用することができます(私はTypeSafeMatcherを使用してコレクション内の項目をテストします)。

私は1つのベストスーツニーズを決定するためにあなたを残しておきますが、私は私の例えばcontainsを使用します:私も過去にこの問題に直面していると私は完全だと同意

List<Record> actual = sut.findBySomeId(); 

Record expected1 = aRecord()...build(); 
Record expected2 = aRecord()...build(); 

assertThat(actual, contains(matchingRecord(expected1), matchingRecord(expected2)); 

... 

// somewhere the test has access to it 
private Matcher<Record> matchingRecord(Record expected) { 
    return new TypeSafeMatcher<Record>() { 
     public boolean matchesSafely(Record actual) { 
      // perform tests and return result, e.g. 
      return actual.getValue() == expected.getValue(); 
     } 

     public void describeMismatchSafely(Record record, Description mismatchDescription) { 
      mismatchDescription.appendText("give a meaningful message"); 
     } 
    }; 

} 
+0

私は、 'Matcher'の' matchesSafely'メソッドで 'ReflectionEquals'を使用できない理由はないと付け加えたいと思います –

0

テスト目的のみのためにequals()hashCode()を実装することは、コードの匂いです。私はHamcrestライブラリを使用していませんので、私は自分のプロジェクトでうまく使用するカスタムソリューションを提供し、その使用法については私はそれに非常に満足しています。あなたが見ることができるように

public static <E, A> void assertListEquals(BiConsumer<E, A> asserter, List<E> expected, List<A> actual) throws AssertionError { 
    assertEquals(
      "Lists have different sizes. Expected list: " + expected + ", actual list: " + actual, 
      expected.size(), 
      actual.size()); 

    for (int i = 0; i < expected.size(); i++) { 
     try { 
      asserter.accept(expected.get(i), actual.get(i)); 
     } catch (AssertionError e) { 
      throw e; 
     } 
    } 
} 

は、BiConsumerは、2つのオブジェクトの等価性をチェックするためのロジックを適用するために使用されています。したがって、このクラスはテストクラスで実装する必要があります。その利点は、2つのオブジェクトを比較するときに興味のあるクラスのフィールドを定義できることです。

使用方法は次のとおりです。 まず、カスタムクラスf.e.があります。:私はテスト(およびTDD)の大ファンですので、私はいつも私のヘルパーメソッドを作るので、私はいつもテストのトンを書く

@Test 
public void peopleLiveInTheVillage_findPeople_peopleAreFound() throws Exception { 
    //Arrange 
    List<Person> expectedPeople = Arrays.asList(
      new Person("Lewis", "Smith", 20), 
      new Person("Steven", "Richard", 25), 
      new Person("Richie", "Rich", 30)); 

    //Act 
    List<Person> actualPeople = sut.findPeople(); 

    //Assert 
    assertListEquals(
      (e, a) -> assertPersonEquals(e, a), 
      expectedPeople, 
      actualPeople); 
} 

private void assertPersonEquals(Person expected, Person actual) { 
    assertEquals(expected.getFirstName(), actual.getFirstName()); 
    assertEquals(expected.getLastName(), actual.getLastName()); 
    assertEquals(expected.getAge(), actual.getAge()); 
} 

:人

public class Person { 
    private String firstName; 
    private String lastName; 
    private int age; 

    public Person(String firstName, String lastName, int age) { 
     this.firstName = firstName; 
     this.lastName = lastName; 
     this.age = age; 
    } 

    public String getFirstName() { 
     return firstName; 
    } 

    public String getLastName() { 
     return lastName; 
    } 

    public int getAge() { 
     return age; 
    } 
} 

は、その後の試験方法を見ることができますBiConsumerをラップしてください:

private void assertPeopleEqual(List<Person> expectedPeople, List<Person> actualPeople) throws AssertionError { 
    assertListEquals(
      (e, a) -> assertPersonEqual(e, a), 
      expectedPeople, 
      actualPeople); 
} 

私はこれがうまくいったら賞賛します!

関連する問題