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


429

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

それが提供するassertNotSame(に相当assertSame)とassertFalse(に相当assertTrue)、彼らが含めて気にしなかったことを奇妙に思えますassertNotEqual

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


少なくともJUnit 4.12以降、assertNotEqualsが提供されています。 junit.org/junit4/javadoc/4.12/org/junit/...
WebF0x

回答:


403

新しい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.*;

134
代替のアサーション構文へのポインターに感謝しますが、他の場所を指してもJUnitが提供されなかった理由はわかりませんassertNotEquals()
10

14
@seh:私がそれを読む方法は、歴史的な関心についてではなく、JUnitテストで「これらの2つのオブジェクトは等しくない」という表明を定式化する方法についての質問でした。私はそう答えました。「なぜ/なかったのか」を考えると、それはassertNotEqualそれほど頻繁に必要とされないassertEquals、したがってジェネリックを介して表現される特殊なアサートだからですassertFalse
Joachim Sauer、

21
「最も読みやすいものを選択してください」。単体テストを読み書きする人はプログラマーです。彼らはこれがassertNotEqual(objectUnderTest、someOtherObject)やassertFalse(objectUnderTest.equals(someOtherObject))よりも読みやすいと本当に思っていますか?私は派手なマッチャーAPIに確信が
持て

@bacar:一部のアサートでは、基本的にはスタイルの問題です。しかしassertThatassert*利用できるメソッドの制限されたセットよりもはるかに表現力があります。したがって、正確な制約を1行で表現し、それを(ほとんど)英語の文のように読み取らせ 、アサートが失敗したときに意味のあるメッセージ取得できます。確かに、それは常にキラー機能とは限りませんが、数回動作しているのを見たときに、どれだけの付加価値があるかがわかります。
Joachim Sauer

5
@Joachim私はそれassertThatがより表現力に富んでいることに同意しassert*ますがassert*、一般的に式の内外に置くことができるJava式ほど表現力があるとは思いません(結局、Javaコードで何かを表現できるからです)。これは、私が流暢なスタイルのAPIに遭遇し始めた一般的な問題です-すべてのAPIは基本的に、習得する必要がある新しいDSLです(Javaがすでにわかっている場合は!)。けれども今や、ハムクレストは至る所に存在していると思いますが、人々にそれを知ってもらうことを期待するのは理にかなっています。私は遊びます...
12

154

あるassertNotEqualsJUnitの4.11では:https://github.com/junit-team/junit/blob/master/doc/ReleaseNotes4.11.md#improvements-to-assert-and-assume

import static org.junit.Assert.assertNotEquals;

1
jmock(2.6.0)のmavenアーティファクトの1つである古いバージョンのjunit-depがリークし、assertNotEqualsのないAssert-classが含まれていることに注意してください。アイビーを使用するときは、それを除外する方が良いでしょう。
gkephorus 2014年

7
4.12を使用していますが、assertNotEqualが見つかりません。:s
ムバシャー

49

同じかな。AssertのAPIはあまり対称的ではありません。オブジェクトが同じかどうかをテストするために、assertSameおよびが提供されassertNotSameます。

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

assertFalse(foo.equals(bar));

このようなアサーションを使用すると、残念ながら出力の情報部分はテストメソッドの名前だけになるため、説明的なメッセージを個別に作成する必要があります。

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

もちろん、これはとても退屈な作業なので、自分でロールする方が良いでしょうassertNotEqual。幸いなことに、将来的にはJUnit:JUnit第22号の一部になる可能性があります。


19
しかし、JUnitは、たとえばfooとbarの等しくない値を通知する有用な失敗メッセージを生成できないため、これはあまり役に立ちません。実際の失敗の理由は隠され、単純なブール値に変わります。
ベンジェームズ

3
全くもって同じ意見です。特に、assertFalseは、実際に何が問題だったかを通知する出力を生成するために、適切なメッセージ引数を必要とします。
ミッコマウヌ

これはテキスト表示テストに役立つと思います。Thnx
Marouane Gazanayi

テキストの問題は、コードが進化するにつれて古くなることです。
Mark Levison、

13

assertNotEqualがないことは確かに非対称であり、JUnitを少し学習しにくくすると私は主張します。メソッドを追加するとAPIの複雑さが減るので、これはきちんとしたケースであることに注意してください。少なくとも私にとっては、対称性は、より大きな空間を支配するのに役立ちます。私の推測では、省略の理由はメソッドを呼び出す人が少なすぎるためかもしれません。それでも、assertFalseさえ存在しなかったときのことを覚えています。したがって、難しい方法ではないので、この方法が最終的に追加される可能性があることを確信しています。エレガントなものであっても、数多くの回避策があることを認めています。


7

私はかなり遅れてこのパーティーに来ていますが、次のようなフォームを見つけました。

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

ほとんどの「等しくない」ケースで機能するようにすることができます。

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

4
これは機能しますが、問題は、アサーションが失敗した場合に、単に「Expcted true、but false was」またはその他の不明確なステートメントと表示されることです。どのような素晴らしいことだと、それはない123期待された場合であるが、た123
ステルスラビ

6

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

私にとって:コンパイラがメソッドassertNotEqualsを見つけることができませんでした
import org.junit.Assert;

だから私は変更
assertNotEquals("addb", string);

Assert.assertNotEquals("addb", string);

したがって、assertNotEqual認識されないという問題に直面している場合は、それを変更しAssert.assertNotEquals(,);て問題を解決する必要があります


1
これは、メソッドが静的であり、静的にインポートする必要があるためです。これimport static org.junit.Assert.*;を使用すると、クラス名なしですべてのアサートを使用できるようになります。
トムストーン

3

人々がassertNotEquals()を必要とした明白な理由は、最初に組み込みオブジェクトを完全なオブジェクトに変換する必要なしに比較するためでした:

詳細な例:

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

assertNotEqual(1, winningBidderId);

悲しいことに、EclipseにはデフォルトでJUnit 4.11が含まれていないため、冗長にする必要があります。

警告 '1'はInteger.valueOf()でラップする必要があるとは思いませんが、.NETから新たに返されたので、自分の正確さを考慮していません。


1

以前のテストレポートではアサーションの失敗の差分が示されるため、assertFalseではなくHamcrestを負のアサーションに使用することをお勧めします。

assertFalseを使用すると、レポートでアサーションエラーが発生するだけです。つまり、失敗の原因に関する情報を失った。


1

通常、これは2つのオブジェクトが等しいことが期待される場合に行います。

assertTrue(obj1.equals(obj2));

そして:

assertFalse(obj1.equals(obj2));

彼らが不平等であると予想されるとき。これはあなたの質問に対する答えではないことは承知していますが、私が得ることができる最も近いものです。JUnit 4.11より前のJUnitバージョンで実行できることを他の人が検索するのに役立ちます。


0

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を使用する方がはるかに明確で柔軟性があります。


-1

Modulo APIの一貫性、JUnitが提供しなかったassertNotEquals()理由は、JUnitが

  • assertStringMatchesTheRegex(regex, str)assertStringDoesntMatchTheRegex(regex, str)
  • assertStringBeginsWith(prefix, str)assertStringDoesntBeginWith(prefix, str)

つまり、アサーションロジックで必要になる可能性のある種類の特定のアサーションメソッドを提供することに終わりはありません。

はるかに良いように構成可能なテスト・プリミティブを提供するためにequalTo(...)is(...)not(...)regex(...)、より読みやすさと正気のために代わりにそれらを一緒プログラマピースをしましょう。


3
まあ、何らかの理由で、assertEquals()が存在します。必要はありませんでしたが、必要でした。問題は対称性の欠如についてでした-なぜassertEqualsは存在するが対応するものが存在しないのですか?
foo
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.