web-dev-qa-db-ja.com

なぜJUnitはassertNotEqualsメソッドを提供しないのですか?

JUnit 4がassertEquals(foo,bar)メソッドを提供し、assertNotEqual(foo,bar)メソッドを提供しない理由を誰かが知っていますか?

assertNotSameassertSameに対応)とassertFalseassertTrueに対応)を提供しているので、それらがassertNotEqualを含めて気にしないのは不思議です。

ところで、私はJUnit-addonsが私が探しているメソッドを提供していることを知っています。私は好奇心から求めています。

413
Chris B

もっと新しい assertThat() スタイルのアサーションを使うことをお勧めします。これはあらゆる種類の否定を簡単に記述し、アサーションが失敗した場合に期待したことと得たことについての記述を自動的に構築します。

assertThat(objectUnderTest, is(not(someOtherObject)));
assertThat(objectUnderTest, not(someOtherObject));
assertThat(objectUnderTest, not(equalTo(someOtherObject)));

3つのオプションはすべて同等です。最も読みやすいものを選択してください。

メソッドの単純な名前を使用する(そしてこの緊張した構文を機能させる)には、以下のインポートが必要です。

import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
392
Joachim Sauer

JUnit 4.11にassertNotEqualsがあります。 https://github.com/junit-team/junit/blob/master/doc/ReleaseNotes4.11.md#improvements-to-assert-and-assume

import static org.junit.Assert.assertNotEquals;
149
Stefan Birkner

私は同じだろうか。 AssertのAPIはあまり対称的ではありません。オブジェクトが同じかどうかをテストするために、assertSameassertNotSameが用意されています。

もちろん、書くのはそれほど長くはありません。

assertFalse(foo.equals(bar));

そのような主張では、残念ながら出力の唯一の有益な部分はテストメソッドの名前なので、説明的なメッセージは別に形成されるべきです:

String msg = "Expected <" + foo + "> to be unequal to <" + bar +">";
assertFalse(msg, foo.equals(bar));

それはもちろんとても面倒なので、あなた自身のassertNotEqualを転がすのが良いです。幸いなことに、将来JUnitの一部になるでしょう。 JUnit issue 22

49
Mikko Maunu

AssertNotEqualが存在しないことは実際には非対称であり、JUnitを少し学習しにくくすると私は主張します。少なくとも私にとっては、メソッドを追加することでAPIの複雑さが軽減される場合、これはきちんとしたケースであることに注意してください。対称性は、より大きなスペースを決定するのに役立ちます。私が思うに、省略の理由は、メソッドを要求している人が少なすぎることにあると思われます。それでも、assertFalseが存在しなかった時代を思い出します。それゆえ、私はこの方法が難しいものではないということを考えれば、この方法が最終的に追加されるかもしれないとの期待を抱いています。たとえエレガントなものであっても、数多くの回避策があることを私は認識していますが。

12

私はもうすぐこのパーティーにやってくるが、その形式は次のようになっている。

static void assertTrue(Java.lang.String message, boolean condition) 

ほとんどの「等しくない」場合に機能するようにできます。

int status = doSomething() ; // expected to return 123
assertTrue("doSomething() returned unexpected status", status != 123 ) ;
7
user903724

私はjUnit4.12を使用して、Java 8環境でJUnitに取り組んでいます。

私のために:私は使用した場合でも、コンパイラはメソッドassertNotEqualsを見つけることができませんでした
import org.junit.Assert;

だから私は変わりました
assertNotEquals("addb", string);

Assert.assertNotEquals("addb", string);

assertNotEqualに関する問題が認識されない場合は、それをAssert.assertNotEquals(,);に変更すると問題が解決します

6

人々がassertNotEquals()を望んだ明白な理由は、最初にそれらを本格的なオブジェクトに変換する必要なしにそれらを比較することでした:

詳細な例:

....
assertThat(1, not(equalTo(Integer.valueOf(winningBidderId))));
....

vs.

assertNotEqual(1, winningBidderId);

残念ながら、EclipseにはデフォルトでJUnit 4.11が含まれていないので、冗長である必要があります。

警告 '1'をInteger.valueOf()でラップする必要はないと思いますが、.NETから新しく返されたので、私の正当性を頼りにしないでください。

3
Mark Levison

前者のテストレポートではアサーション失敗の差分が表示されるため、assertFalseではなくハムクレストを否定的なアサーションに使用することをお勧めします。

AssertFalseを使用すると、レポートにアサーションエラーが発生します。すなわち失敗の原因に関する情報を失った。

1
Chris Kelly

私はOPの見方に完全に同意します。 Assert.assertFalse(expected.equals(actual))は、不平等を表現するための自然な方法ではありません。
しかし、私はAssert.assertEquals()よりもうまくいくが、Assert.assertNotEquals()はテストが実際に主張することを文書化し、主張が失敗したときに/ debugを理解することはユーザーフレンドリーではないと主張するでしょう。
そうはい、JUnit 4.11とJUnit 5はAssert.assertNotEquals()(JUnit 5ではAssertions.assertNotEquals())を提供していますが、私は実際にそれらを使うことを避けます。

別の方法として、オブジェクトの状態をアサートするには、一般に、オブジェクトの状態を簡単に調べられるmatcher APIを使用します。これは、アサーションの意図を明確に文書化し、アサーション失敗の原因を理解するのに非常にユーザーフレンドリーです。

これが一例です。
createWithNewNameAndAge()メソッドをテストしたいAnimalクラスがあるとします。これは、名前と年齢を変更することによって新しいAnimalオブジェクトを作成しますが、好きな食べ物を保持することによって作成します。
私がAssert.assertNotEquals()を使って元のオブジェクトと新しいオブジェクトが異なると主張すると仮定しましょう。
これはcreateWithNewNameAndAge()の不完全な実装を持つAnimalクラスです。

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);
}

テストは期待通りに失敗しますが、開発者に提供された原因は本当に役に立ちません。値は異なるべきであり、実際のAnimalパラメータで呼び出されたtoString()の結果を出力する必要があるとだけ言っています。

Java.lang.AssertionError:値は異なるはずです。実際:動物

[名前=スカビ、年齢= 10、好きな食べ物=干し草]

org.junit.Assert.fail(Assert.Java:88)

[OK]をオブジェクトは等しいではありません。しかし、問題はどこにありますか?
テストしたメソッドでどのフィールドが正しく評価されていませんか? 1 ?二 ?それらのすべて?
それを発見するには、createWithNewNameAndAge()の実装を掘り下げるか、デバッガを使用する必要がありますが、テスト用のAPIは、どちらが期待されるものか、どちらが得られるものかの違いを明らかにします。


テストランナーとしてのJUnit 4.11とアサーションツールとしてのテストMatcher 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、" hay "]>

正確に(そして同じ順序で)含むために:

<["" little scoubi "、1、" hay "]>

しかし、いくつかの要素は見つかりませんでした:

<["" little scoubi "、1]>

そして他の人は予想されていなかった:

<["" scoubi "、10]>

at junit5.MyTest.assertListNotEquals_AssertJ(MyTest.Java:26)

返されたAnimalのAnimal::getName, Animal::getAge, Animal::getFavoriteFood値については、次の値があると期待できます。

"little scoubi", 1, "hay" 

しかし、我々はこれらの値を持っていました:

"scoubi", 10, "hay"

nameageは正しく評価されていません。さらに、Animal::getFavoriteFood()のアサーションでhayの値を指定することで、返されたAnimalをより細かくアサートすることもできます。オブジェクトは、一部のプロパティでは同じではなく、必ずしもすべてのプロパティでは同じではないことが望ましいです。
したがって、matcher APIを使用する方がはるかに明確で柔軟です。

0
davidxxx