JUnit 5: วิธียืนยันข้อยกเว้นถูกโยนทิ้งอย่างไร


214

มีวิธีที่ดีกว่าในการยืนยันว่าวิธีการใดมีข้อยกเว้นใน JUnit 5 หรือไม่?

ขณะนี้ฉันต้องใช้ @Rule เพื่อตรวจสอบว่าการทดสอบของฉันมีข้อยกเว้น แต่ไม่สามารถใช้งานได้ในกรณีที่ฉันคาดว่าจะมีวิธีการมากมายที่จะใช้การยกเว้นในการทดสอบ


1
คุณอาจสนใจตรวจสอบ AssertJ เพื่อตรวจสอบข้อยกเว้นที่ยืดหยุ่นมากกว่า JUnit5
user1075613

คำตอบ:


323

คุณสามารถใช้assertThrows()ซึ่งช่วยให้คุณสามารถทดสอบข้อยกเว้นหลายรายการในการทดสอบเดียวกัน ด้วยการสนับสนุน lambdas ใน Java 8 นี่เป็นวิธีมาตรฐานในการทดสอบข้อยกเว้นใน JUnit

ต่อเอกสาร 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"));
}

11
จากโรงเรียนเก่า "ฉันไม่รู้มากเกี่ยวกับ Junit5 และอาจไม่เพียงพอเกี่ยวกับ Java8" ... นี่มันดูค่อนข้างแปลกประหลาด คุณจะช่วยเพิ่มคำอธิบายเพิ่มเติมได้ไหม; เช่น "ส่วนใดที่มี 'รหัสการผลิต' จริงภายใต้การทดสอบ ... ที่ควรจะโยน"
GhostCat

1
() -> ชี้ไปที่การแสดงออกแลมบ์ดาที่ยอมรับข้อโต้แย้งเป็นศูนย์ ดังนั้น "รหัสการผลิต" ที่คาดว่าจะเกิดข้อยกเว้นอยู่ในบล็อกรหัสที่ชี้ไปที่ (เช่นthrow new...คำสั่งภายในวงเล็บปีกกา)
Sam Brannen

1
โดยทั่วไปการแสดงออกแลมบ์ดาจะโต้ตอบกับวัตถุภายใต้การทดสอบ (SUT) กล่าวอีกนัยหนึ่งการขว้างข้อยกเว้นเช่นเดียวกับข้างต้นโดยตรงเป็นเพียงเพื่อจุดประสงค์ในการสาธิต
Sam Brannen

1
ดูเหมือนว่า expectThrows ถูกคัดค้าน เอกสารบอกว่าจะใช้ assertThrows () แทนตอนนี้
depsypher

5
ตั้งแต่เวอร์ชัน 5.0.0-M4 คาดหวังว่าจะไม่สามารถใช้Throwsได้อีกต่อไป เพียงassertThrowsที่ได้รับอนุญาต ดูgithub.com/junit-team/junit5/blob/master/documentation/src/docs/… : 'ลบ Assertions.expectThrows () วิธีการที่ไม่สนับสนุน Assertions.assertThrows ()'
gil.fernandes

91

ใน Java 8 และ JUnit 5 (Jupiter) เราสามารถยืนยันข้อยกเว้นดังนี้ การใช้org.junit.jupiter.api.Assertions.assertThrows

สแตติกสาธารณะ <T ขยาย Throwable> T assertThrows (คลาส <T> ประเภทที่คาดไว้, เรียกใช้งานได้)

ยืนยันว่าการเรียกใช้งานไฟล์ปฏิบัติการที่ให้มานั้นมีข้อยกเว้นของประเภทที่คาดไว้และส่งกลับข้อยกเว้น

ถ้าไม่มีข้อยกเว้นถูกโยนหรือถ้ามีข้อยกเว้นชนิดอื่นถูกโยนวิธีการนี้จะล้มเหลว

หากคุณไม่ต้องการทำการตรวจสอบเพิ่มเติมเกี่ยวกับอินสแตนซ์ข้อยกเว้นให้ละเว้นค่าส่งคืน

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

วิธีการที่จะใช้ฟังก์ชั่นการเชื่อมต่อในExecutableorg.junit.jupiter.api

อ้างอิง:


1
ขึ้นไปข้างบนด้วยอันนี้! นี่คือคำตอบที่ดีที่สุดโดยไกลที่มากที่สุด up-to-date กับ JUnit 5. นอกจากนี้ IntelliJ ถูกกลั่นแลมบ์ดาลงยิ่งขึ้นถ้ามีเพียงหนึ่งบรรทัดแลมบ์ดา:assertThrows(NoSuchElementException.class, myLinkedList::getFirst);
anon58192932

26

พวกเขาได้เปลี่ยนเป็น JUnit 5 (คาดว่า: InvalidArgumentException, จริง: เมธอดที่เรียกใช้) และโค้ดมีลักษณะดังนี้:

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

21

ตอนนี้ Junit5 มีวิธียืนยันข้อยกเว้น

คุณสามารถทดสอบได้ทั้งข้อยกเว้นทั่วไปและข้อยกเว้นที่กำหนดเอง

สถานการณ์ข้อยกเว้นทั่วไป:

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

คุณสามารถหาตัวอย่างเพื่อทดสอบ CustomException ได้ที่นี่: ยืนยันตัวอย่างรหัสข้อยกเว้น

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

1
ไม่มีความแตกต่างในวิธีที่ JUnit จัดการข้อยกเว้นในตัวและกำหนดเอง
raindev

9

ฉันคิดว่านี่เป็นตัวอย่างที่ง่ายกว่า

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

โทรget()ในตัวเลือกที่มีที่ว่างเปล่าจะโยน ArrayList ประกาศข้อยกเว้นที่คาดไว้และมอบผู้จัดหาแลมบ์ดา (ไม่รับอาร์กิวเมนต์และส่งคืนค่า)NoSuchElementExceptionassertThrows

ขอบคุณ @prime สำหรับคำตอบของเขาซึ่งฉันหวังว่าจะได้กล่าวต่อไป


1
วิธีการassertThrowsส่งกลับข้อยกเว้นโยน ดังนั้นคุณสามารถทำเช่นNoSuchElementException e = assertThrows(NoSuchElementException.class, () -> opt2.get());นั้นด้านล่างคุณสามารถทำสิ่งที่ยืนยันในวัตถุยกเว้นที่คุณต้องการ
กัปตันแมน

8

assertThrows()คุณสามารถใช้ ตัวอย่างของฉันมาจากเอกสาร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());
}

2

ซับง่ายยิ่งขึ้น ไม่มีการแสดงออกแลมบ์ดาหรือวงเล็บปีกกาที่จำเป็นสำหรับตัวอย่างนี้โดยใช้ Java 8 และ 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()
}

1

ที่จริงฉันคิดว่ามีข้อผิดพลาดในเอกสารประกอบสำหรับตัวอย่างเฉพาะนี้ วิธีการที่คาดไว้คือ Throws

public static void assertThrows(
public static <T extends Throwable> T expectThrows(

3
"วิธีการ Assertions.expectThrows () ที่คัดค้านออกเพื่อสนับสนุน Assertions.assertThrows ()"
Martin Schröder

สำหรับ Junit 5 ตรวจสอบให้แน่ใจว่ามาจาก org.junit.jupiter.api.Assertions ไม่ใช่ org.testng.Assert โครงการของเรามีทั้ง Junit และ TestNG รวมอยู่ด้วยและฉันยังคงได้รับ assertThrows ส่งกลับข้อผิดพลาดเป็นโมฆะจนกว่าฉันจะเปลี่ยนเป็น assertExpects ปรากฎว่าฉันใช้ org.testng.Assert
barryku

-5

นี่เป็นวิธีที่ง่าย

@Test
void exceptionTest() {

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

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

}

จะประสบความสำเร็จก็ต่อเมื่อข้อยกเว้นที่คุณคาดหวังถูกส่งออกไป

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.