JUnit neden assertNotEquals yöntemleri sağlamaz?


429

JUnit 4'ün neden yöntemler sağladığını assertEquals(foo,bar)ancak assertNotEqual(foo,bar)yöntemler sağlamadığını bilen var mı ?

Sağladığı assertNotSame(tekabül assertSame) ve assertFalse(karşılık gelen assertTrueonlar dahil uğraşmadı garip görünüyor böylece) assertNotEqual.

Bu arada, JUnit-eklentilerinin aradığım yöntemleri sağladığını biliyorum. Sadece meraktan soruyorum.


En azından JUnit 4.12'den beri assertNotEquals sağlanır. junit.org/junit4/javadoc/4.12/org/junit/…
WebF0x

Yanıtlar:


403

assertThat()Her türlü olumsuzlukları kolayca tanımlayabilen ve onayladığınız şeyin ve iddianın başarısız olması durumunda aldığınız şeyin otomatik olarak bir tanımını oluşturabilen yeni stil önerilerini kullanmanızı öneririm :

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

Her üç seçenek de eşdeğerdir, en okunabilir bulduğunuzu seçin.

Yöntemlerin basit adlarını kullanmak (ve bu gergin sözdiziminin çalışmasına izin vermek) için şu içe aktarmalara ihtiyacınız vardır:

import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;

134
Alternatif iddia sözdizimi için işaretçiyi takdir ediyorum, ama başka bir yere işaret JUnit neden asla cevap vermez assertNotEquals().
seh

14
@seh: Soruyu okuma şeklim tarihsel ilgi ile ilgili değil, bir JUnit testinde "bu iki nesne eşit değil" iddiasını formüle etmenin bir yoluydu. Buna cevap verdim. "Niçin var / niçin hayır assertNotEqual" diye düşünürüm, çünkü bu assertEquals, jenerik yoluyla ifade edilmesi gerektiği kadar sık ​​ihtiyaç duyulmayan özel bir iddiadır assertFalse.
Joachim Sauer

21
msgstr "en okunabilir bulduğunuzu seçin". Birim okuma ve yazma testleri programcıdır. Bunu gerçekten assertNotEqual (objectUnderTest, someOtherObject) veya assertFalse (objectUnderTest.equals (someOtherObject)) 'den daha okunabilir buluyorlar mı? Süslü eşleştirici API'ları tarafından ikna olmadım - bir programcının bunları nasıl kullanacağını keşfetmesi / keşfetmesi oldukça zor görünüyor ...
bacar

@bacar: bazı iddialar için temelde bir stil meselesidir. Ancak assertThat, assert*mevcut sınırlı yöntem kümesinden çok daha etkileyici . Bu nedenle, tek bir satırda kesin kısıtlamaları ifade o (neredeyse) bir İngiliz cümle gibi okunmasını sağlayabilirsiniz ve assert başarısız olduğunda anlamlı mesajı alır. Verilmiş, bu her zaman katil bir özellik değil, ancak birkaç kez çalışırken gördüğünüzde, ne kadar katma değer sağladığını göreceksiniz.
Joachim Sauer

5
@Joachim Bunun assertThatdaha etkileyici olduğunu kabul ediyorum assert*, ancak assert*genel olarak ifadenin içine ve dışına koyabileceğiniz java ifadesinden daha anlamlı olduğunu düşünmüyorum (sonuçta java kodunda herhangi bir şeyi ifade edebilirim). Akıcı tarzı API'lerle karşılaşmaya başladığım genel bir sorun - her biri temelde öğrenmeniz gereken yeni bir DSL (hepimiz Java'yı zaten bildiğimizde!). Sanırım Hamcrest, insanların bunu bilmesini beklemenin makul olduğu kadar her yerde mevcut. Bir oyun oynayacağım ...
Bacar

154

Var assertNotEquals JUnit 4.11 yılında: https://github.com/junit-team/junit/blob/master/doc/ReleaseNotes4.11.md#improvements-to-assert-and-assume

import static org.junit.Assert.assertNotEquals;

1
Zihin, jmock (2.6.0) maven eserlerinden biri, junit-dep'in eski bir sürümünü sızdırıyor ve bu da assertNotEquals olmadan bir Assert sınıfına sahip. Sarmaşık kullanırken bunu dışlamak daha iyi.
gkephorus

7
4.12 kullanıyorum ama yine de assertNotEqual bulamıyorum. : s
Mübarek

49

Ben de merak ediyorum. Assert'in API'sı çok simetrik değildir; nesnelerin aynı olup olmadığını test etmek içinassertSame ve sağlar assertNotSame.

Tabii ki yazmak çok uzun değil:

assertFalse(foo.equals(bar));

Böyle bir iddia ile, çıktının tek bilgilendirici kısmı maalesef test yönteminin adıdır, bu nedenle açıklayıcı mesaj ayrı olarak oluşturulmalıdır:

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

Bu elbette o kadar sıkıcı ki, kendiniz yuvarlamanız daha iyi assertNotEqual. Neyse ki gelecekte belki JUnit: JUnit sorununun bir parçası olacak 22


19
Ancak bu daha az kullanışlıdır, çünkü JUnit size örneğin foo ve bar eşit olmayan değerlerini söyleyen yararlı bir hata mesajı oluşturamaz. Gerçek başarısızlık nedeni gizlidir ve basit bir boole dönüşür.
Ben James

3
Tamamen katılıyorum. Özellikle assertFalse, neyin gerçekten yanlış gittiğini söylemek için çıktı üretmek için uygun mesaj argümanına ihtiyaç duyar.
Mikko Maunu

Bunun mevcut metin testleri için yararlı olduğunu düşünüyorum. Thnx
Marouane Gazanayi

Metinle ilgili sorun, kod geliştikçe güncelliğini yitirmesidir.
Mark Levison

13

AssertNotEqual'ın yokluğunun gerçekten bir asimetri olduğunu ve JUnit'i biraz daha az öğrenilebilir hale getirdiğini iddia ediyorum. Bir yöntem eklerken, en azından benim için API'nin karmaşıklığını azaltacağı için bunun düzgün bir durum olduğunu unutmayın: Simetri, daha büyük alanın yönetilmesine yardımcı olur. Benim tahminimde, ihmalin nedeni, yöntemi arayan çok az insan olması olabilir. Yine de, assertFalse'ın bile olmadığı bir zamanı hatırlıyorum; bu nedenle, zor bir yöntem olmadığı göz önüne alındığında, yöntemin sonunda eklenebileceğine dair olumlu bir beklentim var; çok sayıda geçici çözüm olduğunu, hatta zarif olanları bile kabul ettim.


7

Bu partiye oldukça geç geliyorum ama formu buldum:

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

çoğu 'eşit değil' dava için işe yarayabilir.

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

4
Bu işe yarar olsa da, sorun, eğer iddia başarısız olursa, sadece "Muafiyet doğru, ama yanlıştı" veya başka bir belirsiz ifade söyleyecektir. Ne büyük olurdu 123 değil bekleniyor, ama 123.
Stealth Haham

6

Java 8 ortamında jUnit4.12 kullanarak JUnit üzerinde çalışıyorum

benim için: derleyici kullandığımda bile assertNotEquals yöntemini bulamadı
import org.junit.Assert;

Bu yüzden değişti
assertNotEquals("addb", string);
etmek
Assert.assertNotEquals("addb", string);

Tanınmayan bir sorunla karşı karşıyaysanız assertNotEqual, Assert.assertNotEquals(,);sorununuzu çözmesi için değiştirin .


1
Çünkü yöntemler statiktir ve bunları statik olarak içe aktarmanız gerekir. Bunu kullanın import static org.junit.Assert.*;ve tüm ekleri sınıf adı olmadan kullanabilirsiniz.
Tom Stone

3

İnsanların assertNotEquals () işlevini istemelerinin bariz nedeni, ilk önce yerleşikleri tam üflemeli nesnelere dönüştürmek zorunda kalmadan karşılaştırmaktı:

Ayrıntılı örnek:

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

vs.

assertNotEqual(1, winningBidderId);

Ne yazık ki Eclipse, varsayılan olarak JUnit 4.11 içermediğinden ayrıntılı olmanız gerekir.

Uyarı '1' bir Integer.valueOf () sarılmış gerektiğini sanmıyorum ama yeni .NET döndüğümden beri benim doğruluk güvenmiyorum.


1

Hamcrest'i, assertFalse yerine negatif iddialar için kullanmak daha iyidir.

AssertFalse kullanırsanız, raporda bir onaylama hatası alırsınız. yani arızanın nedeni hakkında bilgi kaybı.


1

Genellikle iki nesnenin eşit olmasını beklediğimde bunu yaparım:

assertTrue(obj1.equals(obj2));

ve:

assertFalse(obj1.equals(obj2));

eşitsiz olmaları beklendiğinde. Bunun sorunuza bir cevap olmadığının farkındayım ama alabileceğim en yakın şey bu. JUnit 4.11'den önce JUnit sürümlerinde neler yapabileceklerini arayan başkalarına yardımcı olabilir.


0

OP bakış açısına tamamen katılıyorum. Assert.assertFalse(expected.equals(actual))eşitsizliği ifade etmenin doğal bir yolu değildir.
Ama daha o başka iddia ediyorum Assert.assertEquals(), Assert.assertNotEquals()eserlerini fakat test aslında iddia ve onaylama işlemi başarısız olarak / debug anlamaya ne belgeye kullanıcı dostu değildir.
Yani evet JUnit 4.11 ve JUnit 5 sağlar Assert.assertNotEquals()( Assertions.assertNotEquals()JUnit 5'te) ama gerçekten onları kullanmaktan kaçının.

Alternatif olarak, bir nesnenin durumunu iddia etmek için, genel olarak, nesne durumuna kolayca giren, iddiaların amacını açıkça belgeleyen ve onaylama hatasının nedenini anlamak için çok kullanıcı dostu olan bir eşleştirici API'sini kullanıyorum.

İşte bir örnek. Yöntemi
test etmek istediğim bir Animal sınıfım createWithNewNameAndAge()olduğunu, adını ve yaşını değiştirerek ama en sevdiği yemeği koruyarak yeni bir Animal nesnesi oluşturan bir yöntem olduğunu varsayalım . Orijinalin ve yeni nesnelerin farklı olduğunu iddia etmek için
kullandığımı varsayalım Assert.assertNotEquals().
Kusurlu bir uygulaması olan Animal sınıfı 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+ (veya JUnit 5) hem test çalıştırıcısı hem de onaylama aracı olarak

@Test
void assertListNotEquals_JUnit_way() {
    Animal scoubi = new Animal("scoubi", 10, "hay");
    Animal littleScoubi = scoubi.createWithNewNameAndAge("little scoubi", 1);
    Assert.assertNotEquals(scoubi, littleScoubi);
}

Test beklendiği gibi başarısız oluyor, ancak geliştiriciye sağlanan neden gerçekten yardımcı olmuyor. Sadece değerlerin farklı olması gerektiğini ve toString()gerçek Animalparametrede çağrılan sonucu çıkardığını söylüyor :

java.lang.AssertionError: Değerler farklı olmalıdır. Gerçek: Hayvan

[ad = scoubi, yaş = 10, favoriGıda = saman]

org.junit.Assert.fail'da (Assert.java:88)

Tamam, nesneler eşit değil. Ama sorun nerede?
Test edilen yöntemde hangi alan doğru şekilde değerlendirilmiyor? Bir ? İki ? Hepsi ?
Bunu keşfetmek için createWithNewNameAndAge() , test API'sı bizim için beklenen ile kazanılan arasındaki farkı yaparsa çok daha kolay olurken uygulamada bir hata ayıklayıcı kullanmanız / bir hata ayıklayıcı kullanmanız gerekir.


Test koşucusu olarak JUnit 4.11 ve onaylama aracı olarak bir test Matcher API

Burada aynı test senaryosu ancak durumun iddiasını yapmak için AssertJ (mükemmel bir test eşleştirici API) kullanır 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");
}

Elbette test hala başarısız oluyor, ancak bu kez neden açıkça belirtildi:

java.lang.AssertionError:

bekleniyor:

<["scoubi", 10, "saman"]>

tam olarak (ve aynı sırada) içermesi:

<["küçük scoubi", 1, "saman"]>

ancak bazı öğeler bulunamadı:

<["küçük scoubi", 1]>

ve diğerleri beklenmiyordu:

<["scoubi", 10]>

junit5.MyTest.assertListNotEquals_AssertJ (MyTest.java:26)

Animal::getName, Animal::getAge, Animal::getFavoriteFoodDöndürülen Hayvanın değerleri için şu değere sahip olmayı beklediğimizi okuyabiliriz :

"little scoubi", 1, "hay" 

ancak şu değerleri elde ettik:

"scoubi", 10, "hay"

Bu yüzden nerede araştırma yapacağımızı biliyoruz: nameve agedoğru değerlendirilmiyor. Ek olarak, hayiddiası iddiasındaki değeri belirtme gerçeği Animal::getFavoriteFood()aynı zamanda iade edilenin daha hassas bir şekilde iddia edilmesine izin verir Animal. Nesnelerin bazı özellikler için aynı olmasını değil, her özellik için olması gerekmez.
Kesinlikle, bir eşleştirici API kullanmak çok daha net ve esnektir.


-1

Modulo API tutarlılığı, JUnit'in neden sağlamadığı assertNotEquals(), JUnit'in asla

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

yani, onaylama mantığınızda isteyebileceğiniz şeyler için belirli bir onaylama yöntemi sağlamanın sonu yoktur!

Çok daha iyi gibi composable testi temel öğeler sağlamak için equalTo(...), is(...), not(...), regex(...)ve daha okunabilirliği ve aklı yerine birlikte programcı parçayı o edelim.


3
iyi, nedense assertEquals () vardır. Yapmak zorunda değildi, ama öyle. Soru simetri eksikliği ile ilgiliydi - neden assertEquals var ama karşılığı değil?
foo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.