JUnit karışıklığı: 'TestCase genişletir' veya '@Test' kullanın?


152

Ben JUnit doğru kullanımı (veya en azından belgeleri) çok kafa karıştırıcı buldum. Bu soru hem gelecekteki referans hem de gerçek bir soru olarak hizmet ediyor.

Doğru anladıysam, bir JUnit testi oluşturmak ve çalıştırmak için iki ana yaklaşım vardır:

Yaklaşım A (JUnit 3 stili): TestCase'i genişleten bir sınıf oluşturun ve test yöntemlerini kelimeyle başlatın test. Sınıfı bir JUnit Testi (Eclipse içinde) testolarak çalıştırırken , sözcükle başlayan tüm yöntemler otomatik olarak çalıştırılır.

import junit.framework.TestCase;

public class DummyTestA extends TestCase {

    public void testSum() {
        int a = 5;
        int b = 10;
        int result = a + b;
        assertEquals(15, result);
    }
}

Yaklaşım B (JUnit 4 stili): 'normal' bir sınıf oluşturun ve @Testyönteme bir açıklama ekleyin . Yöntemi word ile başlatmanız gerekmediğini unutmayın test.

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

public class DummyTestB {

    @Test
    public void Sum() {
        int a = 5;
        int b = 10;
        int result = a + b;
        assertEquals(15, result);
    }
}

İkisini karıştırmak iyi bir fikir gibi görünmüyor, örneğin bu yığın akışı sorusuna bakın :

Şimdi, sorularım:

  1. Tercih edilen yaklaşım nedir veya ne zaman diğeri yerine birini kullanırsınız?
  2. B Yaklaşımı, @Test ek açıklamasını olduğu gibi genişleterek istisnalar için test yapılmasına izin verir @Test(expected = ArithmeticException.class). Ancak A yaklaşımını kullanırken istisnaları nasıl test edersiniz?
  3. A yaklaşımını kullanırken, bir test paketinde aşağıdaki gibi birkaç test sınıfını gruplayabilirsiniz:

    TestSuite suite = new TestSuite("All tests");
    suite.addTestSuite(DummyTestA.class);
    suite.addTestSuite(DummyTestAbis.class);

    Ancak bu yaklaşım B yaklaşımıyla kullanılamaz (çünkü her test sınıfı TestCase alt sınıfını içermelidir). B yaklaşımı için testleri gruplandırmanın uygun yolu nedir?

Düzenleme: Her iki yaklaşıma JUnit sürümlerini ekledim


Gördüm extends TestCaseve sonra her test @Testsadece bir şeyleri karıştırmak için açıklama ekledi. :)
EM-Creations

Yanıtlar:


119

Ayrımı oldukça kolaydır:

  • genişletme TestCase, birim testlerinin JUnit 3'te yazılma şeklidir (elbette JUnit 4'te hala desteklenmektedir)
  • @Testek açıklama kullanmak JUnit 4 tarafından sunulan yoldur

JUnit 3 (ve / veya Java 5'ten önceki bir Java sürümü) ile uyumluluk gerekmedikçe genel olarak ek açıklama yolunu seçmelisiniz. Yeni yolun birkaç avantajı vardır:

JUnit 3'te beklenen istisnaları test etmek için TestCasemetni açık yapmanız gerekir.

public void testMyException() {
  try {
    objectUnderTest.myMethod(EVIL_ARGUMENT);
    fail("myMethod did not throw an Exception!");
  } catch (MyException e) {
    // ok!
    // check for properties of exception here, if desired
  }
}

JUnit 5 başka bir API değişikliği daha yaptı, ancak yine de ek açıklamalar kullanıyor. Yeni @Testek açıklama org.junit.jupiter.api.Test("eski" JUnit 4 olan org.junit.Test), ama hemen hemen JUnit 4 olan ile aynı şekilde çalışır.


Yararlı ve kapsamlı bir cevap, ama "istisna mesajını kontrol et" i tam olarak anlamıyorum. Sabit kodlu bir dizeye karşı kontrol etmek bir bakım kabusu olacaktır. "Belirli istisna türünüzün özelliklerini kontrol et" anlamına gelmiş olmalısınız.
thSoft

3
@thSoft: Bu genellikle kullanılmaz, ancak bazen istisna yönteminin rahatsız edici alandan bahsettiğinden emin olmak istiyorum. O zaman basit bir assertTrue(e.getMessage().contains("foo"))işe yarayabilir.
Joachim Sauer

1
JUnit4'te bile, mesajı veya istisnanın başka bir özelliğini (neden gibi) kontrol etmeniz gerektiğinde önemli bir deyimdir. expectedTürü için bir yöntem, sadece kontrol eder.
Yishai

@Yishai: bu doğru, ancak yöntem sorunlu girdiye doğru türde Özel Durum atarsa, çoğu zaman zaten memnunum.
Joachim Sauer

Bu nedenle, JUnit 5 istisna testinde önemli bir değişiklik yaptı. assertThrows () harika :-)
Marcus K.

25

JUnit 4 (Ek Açıklama yaklaşımı) tercihim var çünkü daha esnek buluyorum.

JUnit 4'te test paketi oluşturmak istiyorsanız, aşağıdaki gibi tüm testleri gruplandıran bir sınıf oluşturmanız gerekir:

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;


@RunWith(Suite.class)
@SuiteClasses({
    Test1.class,
    Test2.class,
    Test3.class,
    Test4.class
})public class TestSuite
{
 /* empty class */
}

15

Sorunuzun yanıtsız bir kısmı var ve bu da "B yaklaşımı için testleri gruplamanın doğru yolu nedir?"

Resmi yanıt, bir sınıfa @RunWith (Suite.class) ekleyerek ve ardından sınıfları listelemek için @ Suite.SuiteClasses ek açıklamasını kullanmanızdır. JUnit geliştiricileri bunu yapar (bir paketteki her sınıfı manuel olarak listeler). Birçok yönden bu yaklaşım bir gelişmedir, çünkü paket öncesi ve paket davranışlarından sonra eklemek önemsiz ve sezgiseldir (@RunWith ile açıklanan sınıfa bir @BeforeClass ve @AfterClass yöntemi ekleyin - eski TestFixture'dan çok daha iyi ).

Ancak, ek açıklamaların sınıfların listesini dinamik olarak oluşturmanıza izin vermediği ve bu soruna geçici bir çözüm bulmak biraz çirkinleştiği için geriye doğru bir adım vardır. Suite sınıfını alt sınıflara ayırmanız ve alt sınıftaki sınıflar dizisini dinamik olarak oluşturmanız ve Suite yapıcısına iletmeniz gerekir, ancak bu, Suite'in diğer alt sınıflarının (Kategoriler gibi) onunla çalışmadığı ve aslında dinamik Test sınıfı koleksiyonunu desteklemez.


1
Bunun için +1. Bir TestSuite'e Testler eklemek için dinamik bir çözüm yazma görevine girdikten sonra, Testlerimin her birinde TestCase'i genişletmek zorunda kaldım. Bu da, beklenen istisnaları tanımlamak için JUnit4 ek açıklamalarını kullanan daha önceki çalışma birimi Testlerini bozmuştur. Bir Test Suite'i dinamik olarak doldurmanın bir yolunu
aramam

4

JUnit 4'ü kullanmalısınız.

Çok sayıda çerçeve JUnit 3.8 desteğini kullanımdan kaldırmaya başladı.

Bu, Spring 3.0 başvuru belgelerinden alınmıştır:

[Uyarı] Eski JUnit 3.8 sınıf hiyerarşisi kullanımdan kaldırıldı

Genel olarak, yeni bir şeye başlarken her zaman bir çerçevenin en son kararlı sürümünü kullanmaya çalışmalısınız.


1
  1. "Tercih edilen" yaklaşım, 4 Haziran'dan bu yana sunulan ek açıklamaları kullanmak olacaktır. Birçok şeyi kolaylaştırırlar (ikinci sorunuza bakın)

  2. Bunun için basit bir try / catch bloğu kullanabilirsiniz:


public void testForException() {
    try {
        Integer.parseInt("just a string");
        fail("Exception should have been thrown");
    } catch (final Exception e) {
        // expected
    }
}
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.