JUnit 5: Bagaimana cara menyatakan pengecualian dilemparkan?

215

Apakah ada cara yang lebih baik untuk menyatakan bahwa metode melempar pengecualian di JUnit 5?

Saat ini, saya harus menggunakan aturan @ untuk memverifikasi bahwa tes saya melempar pengecualian, tetapi ini tidak berfungsi untuk kasus-kasus di mana saya mengharapkan beberapa metode untuk melemparkan pengecualian dalam pengujian saya.

steventrouble
sumber
1
Anda mungkin tertarik untuk memeriksa AssertJ untuk memeriksa pengecualian karena itu lebih fleksibel daripada JUnit5
user1075613

Jawaban:

325

Anda dapat menggunakan assertThrows(), yang memungkinkan Anda menguji beberapa pengecualian dalam pengujian yang sama. Dengan dukungan untuk lambdas di Jawa 8, ini adalah cara kanonik untuk menguji pengecualian di JUnit.

Per dokumen JUnit :

import static org.junit.jupiter.api.Assertions.assertThrows;

@Test
void exceptionTesting() {
    MyException thrown = assertThrows(
           MyException.class,
           () -> myObject.doThing(),
           "Expected doThing() to throw, but it didn't"
    );

    assertTrue(thrown.getMessage().contains("Stuff"));
}
steventrouble
sumber
11
Dari sekolah tua "Saya tidak tahu banyak tentang Junit5 dan mungkin tidak cukup tentang Java8" ... ini terlihat agak aneh. Maukah Anda menambahkan beberapa penjelasan lagi; seperti "bagian mana di sana adalah 'kode produksi' yang sebenarnya sedang diuji ... yang seharusnya dibuang"?
GhostCat
1
() -> menunjuk ke ekspresi lambda yang menerima nol argumen. Dengan demikian, "kode produksi" yang diharapkan untuk membuang pengecualian ada di blok kode yang ditunjukkan (yaitu, throw new...pernyataan dalam kurung keriting).
Sam Brannen
1
Biasanya ekspresi lambda akan berinteraksi dengan subjek yang diuji (SUT). Dengan kata lain, langsung melempar pengecualian seperti di atas hanya untuk tujuan demonstrasi.
Sam Brannen
1
Sepertinya expectThrows sudah usang. Documents mengatakan untuk menggunakan assertThrows () sebagai gantinya sekarang.
depsypher
5
Pada versi 5.0.0-M4 expectThrows tidak lagi tersedia. Hanya assertThrows yang dibolehkan. Lihat github.com/junit-team/junit5/blob/master/documentation/src/docs/… : ' Metode Penghapusan yang dihilangkan. ExpectThrows () mendukung metode Assertions.assertThrows ()'
gil.fernandes
91

Di Java 8 dan JUnit 5 (Jupiter) kita dapat menyatakan pengecualian sebagai berikut. Menggunakanorg.junit.jupiter.api.Assertions.assertThrows

public static <T extends Throwable> T assertThrows (Kelas <T> expectedType, Executable executable)

Menyatakan bahwa eksekusi yang dapat dieksekusi yang disediakan memberikan pengecualian dari tipe yang diharapkan dan mengembalikan pengecualian.

Jika tidak ada pengecualian yang dilemparkan, atau jika pengecualian dari tipe yang berbeda dilemparkan, metode ini akan gagal.

Jika Anda tidak ingin melakukan pemeriksaan tambahan pada contoh pengecualian, abaikan saja nilai pengembaliannya.

@Test
public void itShouldThrowNullPointerExceptionWhenBlahBlah() {
    assertThrows(NullPointerException.class,
            ()->{
            //do whatever you want to do here
            //ex : objectName.thisMethodShoulThrowNullPointerExceptionForNullParameter(null);
            });
}

Pendekatan itu akan menggunakan Interface Fungsional Executabledi org.junit.jupiter.api.

Merujuk:

utama
sumber
1
Ke atas dengan yang ini! Sejauh ini, inilah jawaban terbaik yang paling mutakhir dengan JUnit 5. Selain itu, IntelliJ sedang mengemburkan lambda lebih jauh jika hanya ada satu baris ke Lambda:assertThrows(NoSuchElementException.class, myLinkedList::getFirst);
anon58192932
26

Mereka telah mengubahnya di JUnit 5 (diharapkan: InvalidArgumentException, aktual: metode yang dipanggil) dan kode terlihat seperti ini:

@Test
public void wrongInput() {
    Throwable exception = assertThrows(InvalidArgumentException.class,
            ()->{objectName.yourMethod("WRONG");} );
}
jstar
sumber
21

Sekarang Junit5 menyediakan cara untuk menegaskan pengecualian

Anda dapat menguji pengecualian umum dan pengecualian khusus

Skenario pengecualian umum:

ExpectGeneralException.java

public void validateParameters(Integer param ) {
    if (param == null) {
        throw new NullPointerException("Null parameters are not allowed");
    }
}

ExpectGeneralExceptionTest.java

@Test
@DisplayName("Test assert NullPointerException")
void testGeneralException(TestInfo testInfo) {
    final ExpectGeneralException generalEx = new ExpectGeneralException();

     NullPointerException exception = assertThrows(NullPointerException.class, () -> {
            generalEx.validateParameters(null);
        });
    assertEquals("Null parameters are not allowed", exception.getMessage());
}

Anda dapat menemukan sampel untuk menguji CustomException di sini: menegaskan contoh kode pengecualian

ExpectCustomException.java

public String constructErrorMessage(String... args) throws InvalidParameterCountException {
    if(args.length!=3) {
        throw new InvalidParameterCountException("Invalid parametercount: expected=3, passed="+args.length);
    }else {
        String message = "";
        for(String arg: args) {
            message += arg;
        }
        return message;
    }
}

ExpectCustomExceptionTest.java

@Test
@DisplayName("Test assert exception")
void testCustomException(TestInfo testInfo) {
    final ExpectCustomException expectEx = new ExpectCustomException();

     InvalidParameterCountException exception = assertThrows(InvalidParameterCountException.class, () -> {
            expectEx.constructErrorMessage("sample ","error");
        });
    assertEquals("Invalid parametercount: expected=3, passed=2", exception.getMessage());
}
Anupama Boorlagadda
sumber
1
Tidak ada perbedaan dalam cara JUnit menangani pengecualian bawaan dan kustom.
raindev
9

Saya pikir ini adalah contoh yang lebih sederhana

List<String> emptyList = new ArrayList<>();
Optional<String> opt2 = emptyList.stream().findFirst();
assertThrows(NoSuchElementException.class, () -> opt2.get());

Memanggil get()opsional yang berisi kosong ArrayListakan melempar a NoSuchElementException. assertThrowsmendeklarasikan pengecualian yang diharapkan dan memberikan pemasok lambda (tidak mengambil argumen dan mengembalikan nilai).

Terima kasih kepada @prime atas jawabannya yang mudah-mudahan saya uraikan.

JesseBoyd
sumber
1
metode assertThrowsmengembalikan pengecualian yang dilemparkan. Jadi, Anda dapat melakukannya seperti di NoSuchElementException e = assertThrows(NoSuchElementException.class, () -> opt2.get());bawah ini. Anda dapat melakukan semacam pernyataan tentang objek pengecualian yang Anda inginkan.
Kapten Man
8

Anda bisa menggunakannya assertThrows(). Contoh saya diambil dari dokumen http://junit.org/junit5/docs/current/user-guide/

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

....

@Test
void exceptionTesting() {
    Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
        throw new IllegalArgumentException("a message");
    });
    assertEquals("a message", exception.getMessage());
}
Will Humphreys
sumber
2

Satu liner yang bahkan lebih sederhana. Tidak diperlukan ekspresi lambda atau kurung kurawal untuk contoh ini menggunakan Java 8 dan JUnit 5

import static org.junit.jupiter.api.Assertions.assertThrows;

@Test
void exceptionTesting() {

    assertThrows(MyException.class, myStackObject::doStackAction, "custom message if assertion fails..."); 

// note, no parenthesis on doStackAction ex ::pop NOT ::pop()
}
rnyunja
sumber
1

Sebenarnya saya pikir ada kesalahan dalam dokumentasi untuk contoh khusus ini. Metode yang dimaksudkan adalah expectThrows

public static void assertThrows(
public static <T extends Throwable> T expectThrows(
Peter Isberg
sumber
3
"Dihapus metode Assertions.expectThrows () yang dihapus mendukung Assertions.assertThrows ()."
Martin Schröder
Untuk Junit 5, pastikan itu dari org.junit.jupiter.api.Assertions bukan org.testng.Assert. Proyek kami menyertakan Junit dan TestNG, dan saya terus mendapatkan assertThrows mengembalikan galat hingga saya mengubahnya ke assertExpects. Ternyata saya menggunakan org.testng.Assert.
barryku
-5

Ini cara yang mudah.

@Test
void exceptionTest() {

   try{
        model.someMethod("invalidInput");
        fail("Exception Expected!");
   }
   catch(SpecificException e){

        assertTrue(true);
   }
   catch(Exception e){
        fail("wrong exception thrown");
   }

}

Itu hanya berhasil ketika Pengecualian yang Anda harapkan dilemparkan.

kiwicomb123
sumber