Khẳng định một ngoại lệ bằng XUnit


111

Tôi là người mới sử dụng XUnit và Moq. Tôi có một phương thức lấy chuỗi làm đối số. Cách xử lý ngoại lệ bằng 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(""));
}

Phương pháp đang thử nghiệm

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
Ý bạn là gì khi "không hoạt động như mong đợi"? (Ngoài ra, xin vui lòng định dạng mã của bạn readably hơn Sử dụng bản xem trước, và sau khi nó trông như thế nào bạn muốn nó để xem xét nếu bạn đang đọc nó..)
Jon Skeet

4
Gợi ý: bạn đang gọi GetSettingsForUserID("")trước khi bắt đầu gọi Assert.Throws. Cuộc Assert.Throwsgọi không thể giúp bạn ở đó. Tôi muốn đề nghị là ít cứng nhắc về AAA ...
Jon Skeet

Câu trả lời:


183

Các Assert.Throws biểu sẽ bắt ngoại lệ và khẳng định loại. Tuy nhiên, bạn đang gọi phương thức đang được kiểm tra bên ngoài biểu thức khẳng định và do đó không thực hiện được trường hợp kiểm tra.

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

Nếu muốn theo dõi AAA, bạn có thể trích xuất hành động vào biến riêng của nó.

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

Lưu ý cách ngoại lệ cũng có thể được sử dụng cho các xác nhận chi tiết về chế độ


5
Nếu sử dụng các phương pháp không đồng bộ, Visual Studio đưa ra một cảnh báo với cú pháp trên. Nó thích điều này hơn:async Task act() => await service.DoTheThingAsync(); await Assert.ThrowsAsync<InvalidOperationException>(act);
Alec

5
Trên thực tế, đối với tôi, điều đó đã dẫn đến lỗi, 'không thể chuyển đổi ngầm Task thành Func <Task>', trong khi nếu tôi chỉ cần đặt Task act() => service.DoTheThingAsync(); await Assert.ThrowsAsync<InvalidOperationException>(act);thì nó hài lòng với điều đó và hoạt động tốt.
Alec,

làm việc với async / await tác động đến điều này như thế nào? khi tôi thử thực hiện việc này bằng ThrowsAsync trong thử nghiệm của mình, nó không bao giờ đạt đến dòng Assert.Equal vì nó ném lỗi thành công và thoát thử nghiệm. thử nghiệm nước để xem liệu đây có phải là một câu hỏi mới ...
nathanjw

@AlecDenholm Cảm ơn! Đó là điều duy nhất làm việc cho tôi. Tôi nghĩ rằng một số đề xuất khác không thực sự hoạt động bình thường đối với nội dung không đồng bộ.
nhãn hiệu

45

Nếu bạn muốn cứng nhắc về AAA thì bạn có thể sử dụng Record.Exception từ xUnit để nắm bắt Ngoại lệ trong giai đoạn Hành động của bạn.

Sau đó, bạn có thể đưa ra các xác nhận dựa trên ngoại lệ đã thu được trong giai đoạn Assert.

Một ví dụ về điều này có thể được nhìn thấy trong các bài kiểm tra xUnits .

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

    var ex = Record.Exception(testCode);

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

Bạn muốn đi theo con đường nào tùy thuộc vào bạn và cả hai đường dẫn đều được hỗ trợ đầy đủ bởi những gì xUnit cung cấp.


1
FWIW, Giải pháp này rất tuyệt nếu bạn cần xác thực thông báo ngoại lệ, v.v. Tôi nghĩ đó là lúc bạn có thể sử dụng Record.Exception.
Jeff LaFay

@JeffLaFay Tôi đánh giá cao tôi hơi trễ đến bữa tiệc ở đây, điều đó sẽ khác với việc sử dụng var exception = Assert.Throws<InvalidOperationException>(testCode);và xác nhận trên exception.Messagenhư thế nào? hay nó chỉ là một hương vị khác của việc đạt được điều tương tự?
ColinM

3

Bạn có thể xem xét một cái gì đó như thế này nếu bạn muốn gắn bó với AAA:

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

// Assert
await Assert.ThrowsAsync<MyExpectedException>(act);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.