ยืนยันข้อยกเว้นโดยใช้ XUnit


111

ฉันเป็นมือใหม่สำหรับ XUnit และ Moq ฉันมีวิธีการที่ใช้สตริงเป็นอาร์กิวเมนต์วิธีจัดการข้อยกเว้นโดยใช้ XUnit

[Fact]
public void ProfileRepository_GetSettingsForUserIDWithInvalidArguments_ThrowsArgumentException() {
    //arrange
    ProfileRepository profiles = new ProfileRepository();
    //act
    var result = profiles.GetSettingsForUserID("");
    //assert
    //The below statement is not working as expected.
    Assert.Throws<ArgumentException>(() => profiles.GetSettingsForUserID(""));
}

วิธีการทดสอบ

public IEnumerable<Setting> GetSettingsForUserID(string userid)
{            
    if (string.IsNullOrWhiteSpace(userid)) throw new ArgumentException("User Id Cannot be null");
    var s = profiles.Where(e => e.UserID == userid).SelectMany(e => e.Settings);
    return s;
}

1
"ไม่ทำงานตามที่คาดไว้" หมายความว่าอย่างไร (นอกจากนี้โปรดจัดรูปแบบโค้ดของคุณให้อ่านง่ายขึ้นใช้การแสดงตัวอย่างและโพสต์เมื่อมีลักษณะที่คุณต้องการให้ดูเหมือนว่าคุณกำลังอ่านอยู่หรือไม่)
Jon Skeet

4
คำแนะนำ: คุณโทรก่อนที่คุณจะเริ่มเรียกGetSettingsForUserID("") Assert.ThrowsการAssert.Throwsโทรไม่สามารถช่วยคุณได้ ฉันขอแนะนำให้เข้มงวดน้อยลงเกี่ยวกับ AAA ...
Jon Skeet

คำตอบ:


184

Assert.Throwsแสดงออกจะจับข้อยกเว้นและยืนยันชนิด อย่างไรก็ตามคุณกำลังเรียกใช้เมธอดภายใต้การทดสอบนอกนิพจน์ยืนยันและทำให้กรณีทดสอบล้มเหลว

[Fact]
public void ProfileRepository_GetSettingsForUserIDWithInvalidArguments_ThrowsArgumentException()
{
    //arrange
    ProfileRepository profiles = new ProfileRepository();
    // act & assert
    Assert.Throws<ArgumentException>(() => profiles.GetSettingsForUserID(""));
}

หากยึดตาม AAA คุณสามารถแยกการกระทำเป็นตัวแปรของตัวเองได้

[Fact]
public void ProfileRepository_GetSettingsForUserIDWithInvalidArguments_ThrowsArgumentException()
{
    //arrange
    ProfileRepository profiles = new ProfileRepository();
    //act
    Action act = () => profiles.GetSettingsForUserID("");
    //assert
    var exception = Assert.Throws<ArgumentException>(act);
    //The thrown exception can be used for even more detailed assertions.
    Assert.Equal("expected error message here", exception.Message);
}

โปรดสังเกตว่าสามารถใช้ข้อยกเว้นสำหรับการยืนยันโดยละเอียดของโหมดได้อย่างไร


5
หากใช้วิธีการ async Visual Studio จะแสดงคำเตือนด้วยไวยากรณ์ข้างต้น มันชอบสิ่งนี้:async Task act() => await service.DoTheThingAsync(); await Assert.ThrowsAsync<InvalidOperationException>(act);
อเล็กซ์

5
ที่จริงแล้วสำหรับฉันที่ทำให้เกิดข้อผิดพลาด 'ไม่สามารถแปลงงานเป็น Func <Task> โดยปริยายได้โดยปริยายในขณะที่ฉันใส่แค่Task act() => service.DoTheThingAsync(); await Assert.ThrowsAsync<InvalidOperationException>(act);นั้นก็พอใจแล้วและทำงานได้ดี
Alec

การทำงานกับ async / await ส่งผลต่อสิ่งนี้อย่างไร เมื่อฉันลองทำสิ่งนี้โดยใช้ ThrowsAsync ในการทดสอบของฉันมันไม่เคยไปถึง Assert บรรทัดเท่ากับเมื่อมันส่งข้อผิดพลาดสำเร็จและออกจากการทดสอบ ทดสอบน้ำเพื่อดูว่าควรจะเป็นคำถามใหม่หรือไม่ ...
nathanjw

@AlecDenholm ขอบคุณ! นั่นเป็นสิ่งเดียวที่เหมาะกับฉัน ฉันคิดว่าคำแนะนำอื่น ๆ บางอย่างใช้ไม่ได้จริงสำหรับสิ่งที่ไม่ซิงค์
เครื่องหมายการค้า

45

หากคุณต้องการเข้มงวดเกี่ยวกับ AAA คุณสามารถใช้Record.Exceptionจาก xUnit เพื่อจับ Exception ในขั้นตอน Act ของคุณ

จากนั้นคุณสามารถทำการยืนยันตามข้อยกเว้นที่จับได้ในขั้นตอน Assert

ตัวอย่างนี้สามารถเห็นได้ในการทดสอบ xUnits

[Fact]
public void Exception()
{
    Action testCode = () => { throw new InvalidOperationException(); };

    var ex = Record.Exception(testCode);

    Assert.NotNull(ex);
    Assert.IsType<InvalidOperationException>(ex);
}

ขึ้นอยู่กับคุณว่าคุณต้องการเดินตามเส้นทางใดและทั้งสองเส้นทางได้รับการสนับสนุนอย่างเต็มที่จากสิ่งที่ xUnit จัดเตรียมไว้ให้


1
FWIW โซลูชันนี้ดีมากหากคุณจำเป็นต้องตรวจสอบความถูกต้องของข้อความยกเว้น ฯลฯ ฉันคิดว่านั่นคือเวลาที่คุณอาจใช้ Record.Exception
Jeff LaFay

@JeffLaFay ฉันขอขอบคุณที่ฉันไปงานปาร์ตี้ที่นี่ช้าไปหน่อยมันจะแตกต่างจากการใช้var exception = Assert.Throws<InvalidOperationException>(testCode);และการยืนยันexception.Messageอย่างไร? หรือเป็นเพียงรสชาติของการบรรลุสิ่งเดียวกัน?
ColinM

3

คุณสามารถพิจารณาสิ่งนี้ได้หากคุณต้องการยึดติดกับ AAA:

// Act 
Task act() => handler.Handle(request);

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