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
"예상대로 작동하지 않음"이란 무엇을 의미합니까? (. 그것은 당신이 당신이 그것을 읽는다면이보고 싶어 방법을 찾을 때 또한, 미리보기를 사용하여 더 판독 가능 코드를 포맷하고, 게시하시기 바랍니다.)
존 소총을

4
힌트 : 전화를 걸기 GetSettingsForUserID("")전에 전화를 거는 것 Assert.Throws입니다. Assert.Throws전화가 당신을 도울 수 있습니다. 나는 ... AAA에 대해 덜 경직되고 좋을 것
존 소총을

답변:


183

Assert.Throws의 표현은 예외를 잡아 유형을 주장한다. 그러나 assert 식 외부에서 테스트중인 메서드를 호출하므로 테스트 케이스가 실패합니다.

[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
비동기 메서드를 사용하는 경우 Visual Studio는 위 구문으로 경고를 표시합니다. 다음을 선호합니다.async Task act() => await service.DoTheThingAsync(); await Assert.ThrowsAsync<InvalidOperationException>(act);
Alec

5
실제로 오류가 발생한 나를 위해 '암묵적으로 Task를 Func <Task>로 변환 할 수 없습니다 Task act() => service.DoTheThingAsync(); await Assert.ThrowsAsync<InvalidOperationException>(act);.
Alec

async / await로 작업하면 어떻게 영향을 받습니까? 내 테스트에서 ThrowsAsync를 사용하여 이것을 시도하면 성공적으로 오류를 던지고 테스트를 종료하므로 Assert.Equal 줄에 도달하지 않습니다. 물을 테스트하여 이것이 새로운 질문이되어야하는지 확인합니다 ...
nathanjw

@AlecDenholm 감사합니다! 그것이 나를 위해 일한 유일한 것입니다. 다른 제안 중 일부는 비동기 작업에 대해 제대로 작동하지 않는다고 생각합니다.
상표권

45

AAA에 대해 엄격하게 알고 싶다면 xUnit의 Record.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.