OPの観点に完全に同意します。 Assert.assertFalse(expected.equals(actual))
不平等を表現する自然な方法ではありません。
しかし、私はよりその更を主張するだろうAssert.assertEquals()
、 Assert.assertNotEquals()
作品をしかしテストは、実際にアサートし、アサーションが失敗したとして/デバッグを理解するためにどのような文書にユーザーフレンドリーではありません。
つまり、JUnit 4.11とJUnit 5はAssert.assertNotEquals()
(Assertions.assertNotEquals()
JUnit 5で)が、私はそれらの使用を本当に避けています。
別の方法として、オブジェクトの状態をアサートするために、オブジェクトの状態を簡単に掘り下げるマッチャーAPIを一般的に使用し、アサーションの意図を明確に文書化し、アサーションエラーの原因を理解するのに非常にユーザーフレンドリーです。
ここに例があります。メソッド
をテストしたいAnimalクラスがあるとします。このcreateWithNewNameAndAge()
メソッドは、名前と年齢を変更して、お気に入りの食べ物を保持することによって、新しいAnimalオブジェクトを作成します。元のオブジェクトと新しいオブジェクトが異なると主張
するAssert.assertNotEquals()
ために使用 するとします。
以下は、欠陥のある実装のAnimalクラスですcreateWithNewNameAndAge()
。
public class Animal {
private String name;
private int age;
private String favoriteFood;
public Animal(String name, int age, String favoriteFood) {
this.name = name;
this.age = age;
this.favoriteFood = favoriteFood;
}
// Flawed implementation : use this.name and this.age to create the
// new Animal instead of using the name and age parameters
public Animal createWithNewNameAndAge(String name, int age) {
return new Animal(this.name, this.age, this.favoriteFood);
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getFavoriteFood() {
return favoriteFood;
}
@Override
public String toString() {
return "Animal [name=" + name + ", age=" + age + ", favoriteFood=" + favoriteFood + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((favoriteFood == null) ? 0 : favoriteFood.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Animal)) return false;
Animal other = (Animal) obj;
return age == other.age && favoriteFood.equals(other.favoriteFood) &&
name.equals(other.name);
}
}
テストランナーおよびアサーションツールとしてのJUnit 4.11+(またはJUnit 5)
@Test
void assertListNotEquals_JUnit_way() {
Animal scoubi = new Animal("scoubi", 10, "hay");
Animal littleScoubi = scoubi.createWithNewNameAndAge("little scoubi", 1);
Assert.assertNotEquals(scoubi, littleScoubi);
}
テストは期待どおりに失敗しますが、開発者に提供された原因は本当に役に立ちません。値が異なる必要がありtoString()
、実際のAnimal
パラメーターで呼び出された結果を出力するだけです。
java.lang.AssertionError:値は異なる必要があります。実際:動物
[name = scoubi、age = 10、favoriteFood = hay]
org.junit.Assert.fail(Assert.java:88)で
オブジェクトは等しくありません。しかし、問題はどこにありますか?
テストされた方法で正しく評価されないフィールドはどれですか?1 ?二 ?それらすべて?
それを発見するには、createWithNewNameAndAge()
実装を掘り下げてデバッガを使用する必要がありますが、テスト用APIは、期待されるものと得られるものとの違いが見つかれば、はるかに友好的です。
テストランナーとしてのJUnit 4.11およびアサーションツールとしてのテストマッチャーAPI
ここではテストの同じシナリオですが、AssertJ(優れたテストマッチャーAPI)を使用してAnimal
状態のアサーションを作成します。
import org.assertj.core.api.Assertions;
@Test
void assertListNotEquals_AssertJ() {
Animal scoubi = new Animal("scoubi", 10, "hay");
Animal littleScoubi = scoubi.createWithNewNameAndAge("little scoubi", 1);
Assertions.assertThat(littleScoubi)
.extracting(Animal::getName, Animal::getAge, Animal::getFavoriteFood)
.containsExactly("little scoubi", 1, "hay");
}
もちろんテストはまだ失敗しますが、今回は理由が明確に述べられています:
java.lang.AssertionError:
期待:
<["scoubi"、10、 "干し草"]>
正確に(そして同じ順序で)含む:
<["little scoubi"、1、 "hay"]>
しかし、いくつかの要素が見つかりませんでした:
<["little scoubi"、1]>
その他は期待されていませんでした:
<["scoubi"、10]>
junit5.MyTest.assertListNotEquals_AssertJ(MyTest.java:26)で
私たちは、のためにすることを読み取ることができますAnimal::getName, Animal::getAge, Animal::getFavoriteFood
返された動物の値、我々はこれらの値を持つことを期待します:
"little scoubi", 1, "hay"
しかし、私たちはこれらの値を持っていました:
"scoubi", 10, "hay"
だから私たちはどこを調査するかを知っています:name
そしてage
正しく評価されていません。さらに、のhay
アサーションで値を指定することにより、返されたAnimal::getFavoriteFood()
をより細かくアサートすることもできますAnimal
。一部のプロパティではオブジェクトが同じでなくても、すべてのプロパティで同じである必要はないことを望みます。
つまり、マッチャーAPIを使用する方がはるかに明確で柔軟性があります。