ใช้วิธีการ NUnit Assert.Throws หรือแอตทริบิวต์ ExpectedException หรือไม่


146

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

Assert.Throws<Exception>(()=>MethodThatThrows());

[ExpectedException(typeof(Exception))]

ข้อใดจะดีที่สุด ข้อเสนอหนึ่งมีข้อได้เปรียบเหนือสิ่งอื่นหรือไม่? หรือมันเป็นเพียงเรื่องของการตั้งค่าส่วนตัว?


3
ตัวเลือกที่ 3 คือสไตล์ที่คล่องแคล่ว:Assert.That(() => MethodThatThrows(), Throws.Exception)
Jack Ukleja

1
NUnit เวอร์ชัน 3 และใหม่กว่าไม่สนับสนุนExpectedExceptionแอตทริบิวต์อีกต่อไปดังนั้นสำหรับรุ่น 3 ขึ้นไปเฉพาะAssert.Throwsรุ่นที่เกี่ยวข้องเท่านั้น
joanlofe

ทำไมถึงเป็นเช่นนั้น? Nunit3 นั้นตัดสินใจทิ้งการสนับสนุนนั้นหรือไม่ กำลัง googling ไปรอบ ๆ และไม่สามารถหาคำอธิบายได้ ... JUnit ยังคงสนับสนุนวิธีนี้ใช่ไหม
ahaaman

คำตอบ:


92

วิธีแรกให้คุณทดสอบมากกว่าหนึ่งข้อยกเว้นด้วยการโทรหลายสาย:

Assert.Throws(()=>MethodThatThrows());
Assert.Throws(()=>Method2ThatThrows());

ข้อที่สองให้คุณทดสอบข้อยกเว้นหนึ่งข้อต่อหนึ่งฟังก์ชั่นการทดสอบเท่านั้น


25
การทดสอบควรทดสอบตรรกะหนึ่งบิตที่แตกต่างกันเท่านั้นดังนั้นการทดสอบหน่วยข้อผิดพลาดสองครั้งในการทดสอบหน่วยเดียวกันจะไม่ถือว่าเป็นการปฏิบัติที่ไม่ดีหรือไม่
SamuelDavis

5
@SamuelDavis - โดยทั่วไปคุณไม่ต้องการทดสอบกรณีอื่นในการทดสอบเดียวกัน Assert.Throwsแต่อาจจะมีกรณีการใช้งานบางอย่างสำหรับหลาย ๆ
chue x

3
ทั้งสองวิธีที่นี่คุณจะได้รับการยกเว้นเป็นพารามิเตอร์ซึ่งช่วยให้คุณสามารถยืนยันรายละเอียดในข้อยกเว้น นอกจากนี้การใช้ "ข้อยกเว้นที่คาดไว้" ไม่ได้ป้องกันคุณสำหรับประเภทข้อยกเว้นเดียวกันที่ถูกส่งออกไปในการเรียกใช้เมธอดอื่น ที่นี่คุณกำหนดเป้าหมายวิธีที่แน่นอนไม่ใช่การทดสอบทั้งหมด แม้ว่าการทดสอบของคุณจะเรียกรหัสน้อยมาก แต่คุณก็ไม่เคยปลอดภัยเกินไป โดยเฉพาะอย่างยิ่งเมื่อรหัสซับซ้อนและ / หรือมีข้อยกเว้นทั่วไปเกินไป สิ่งต่าง ๆ เช่น "ArgumentNullExceptions" สามารถถูกส่งออกไปได้จำนวนมากและตัวอย่างเช่นจะพลาดได้ง่ายโดยใช้ ExpectedException ยืนยัน. แถวจะไม่พลาดมัน
Gil Sand

254

ความแตกต่างที่สำคัญคือ:

ExpectedException()คุณลักษณะทำให้การทดสอบผ่านหากมีข้อยกเว้นเกิดขึ้นในสถานที่ใด ๆในวิธีการทดสอบ
การใช้งานของAssert.Throws()อนุญาตให้ระบุexactตำแหน่งของรหัสที่คาดว่าจะมีข้อยกเว้น

NUnit 3.0 ลดการสนับสนุนอย่างเป็นทางการสำหรับExpectedExceptionทั้งหมด

ดังนั้นฉันชอบที่จะใช้Assert.Throws()วิธีการมากกว่าExpectedException()แอตทริบิวต์


7
นี่คือคำตอบที่ถูกต้อง อนึ่ง Assert.Throws () จะส่งกลับข้อยกเว้นซึ่งสามารถตรวจสอบคุณสมบัติเพิ่มเติมของข้อยกเว้นได้หากพวกเขามีความสำคัญต่อคุณ
ความสมบูรณ์แบบ

1
สุดท้ายตอบว่าทำไมฉันไม่สามารถรับ ExpectedException เพื่อทำงาน .. กับเวอร์ชัน 3
JanT

2
นี่คือลิงค์github.com/nunit/docs/wiki/Breaking-Changes - ExpectedExceptionAttribute ไม่รองรับอีกต่อไป
Anton Lyhin

หากต้องการเปลี่ยนให้ทำงานภายใต้ NUnit 3.0 ให้เปลี่ยนเป็นดังนี้
Andrei Krasutski

38

ฉันชอบ assert.throws เนื่องจากอนุญาตให้ฉันตรวจสอบและยืนยันเงื่อนไขอื่น ๆ หลังจากมีการโยนข้อยกเว้น

    [Test]
    [Category("Slow")]
    public void IsValidLogFileName_nullFileName_ThrowsExcpetion()
    {
        // the exception we expect thrown from the IsValidFileName method
        var ex = Assert.Throws<ArgumentNullException>(() => a.IsValidLogFileName(""));

        // now we can test the exception itself
        Assert.That(ex.Message == "Blah");

    }

นี่เป็นหนึ่งในคำตอบที่ดีกว่าเป็นเรื่องธรรมดาที่คุณต้องการตรวจสอบว่ามีบางสิ่งที่เข้าสู่สถานะที่มีข้อผิดพลาดหลังจากที่มีการโยนข้อยกเว้น
Rhys Bevilaqua

11

นอกจากนี้คุณยังอาจพิมพ์ข้อผิดพลาดที่คุณคาดหวังได้ (เช่นเวอร์ชัน attrib เก่า)

Assert.Throws<System.InvalidOperationException>(() => breakingAction())

1

หากคุณกำลังใช้รุ่นเก่า ( <= 2.0 ) ของแล้วคุณจะต้องใช้NUnitExpectedException

หากคุณใช้เวอร์ชั่น2.5หรือใหม่กว่าคุณสามารถใช้งานได้Assert.Throw()

https://github.com/nunit/docs/wiki/Breaking-Changes

วิธีใช้: https://www.nunit.org/index.php?p=exceptionAsserts&r=2.5

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