문제

예외가 발생했는지 확인하기 위해 Assert(또는 다른 Test 클래스)를 어떻게 사용합니까?

도움이 되었습니까?

해결책

"Visual Studio Team Test"의 경우 Test의 방법에 ExpecteException 속성을 적용하는 것으로 보입니다.

여기 문서에서 샘플 : Visual Studio 팀 테스트를 통한 단위 테스트 연습

[TestMethod]
[ExpectedException(typeof(ArgumentException),
    "A userId of null was inappropriately allowed.")]
public void NullUserIdInConstructor()
{
   LogonInfo logonInfo = new LogonInfo(null, "P@ss0word");
}

다른 팁

일반적으로 테스트 프레임 워크에는 이에 대한 답이 있습니다. 그러나 충분히 유연하지 않으면 언제든지 할 수 있습니다.

try {
    somethingThatShouldThrowAnException();
    Assert.Fail(); // If it gets to this line, no exception was thrown
} catch (GoodException) { }

@jonas가 지적했듯이 이것은 기본 예외를 포착하는 데 효과적이지 않습니다.

try {
    somethingThatShouldThrowAnException();
    Assert.Fail(); // raises AssertionException
} catch (Exception) {
    // Catches the assertion exception, and the test passes
}

예외를 절대적으로 포착 해야하는 경우 Assert.fail ()를 재검토해야합니다. 그러나 실제로, 이것은 당신이 이것을 손으로 쓰지 말아야하는 신호입니다. 옵션에 대한 테스트 프레임 워크를 확인하거나 더 의미있는 예외를 테스트 할 수 있는지 확인하십시오.

catch (AssertionException) { throw; }

잡을 예외가 어떤 종류의 예외를 지정하는 것을 포함하여, 원하는 대로이 접근법을 원하는대로 조정할 수 있어야합니다. 특정 유형 만 기대하면 catch 다음과 같이 차단합니다.

} catch (GoodException) {
} catch (Exception) {
    // not the right kind of exception
    Assert.Fail();
}

이것을 구현하는 것이 선호하는 방법은 Throws라는 메소드를 작성하고 다른 어제 방법과 마찬가지로 사용하는 것입니다. 불행히도 .NET을 사용하면 정적 확장 방법을 작성할 수 없으므로이 방법이 실제로 Assert 클래스의 빌드에 속하는 것처럼이 방법을 사용할 수 없습니다. MyAssert라는 다른 사람을 만들거나 비슷한 것을 만드십시오. 수업은 다음과 같습니다.

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace YourProject.Tests
{
    public static class MyAssert
    {
        public static void Throws<T>( Action func ) where T : Exception
        {
            var exceptionThrown = false;
            try
            {
                func.Invoke();
            }
            catch ( T )
            {
                exceptionThrown = true;
            }

            if ( !exceptionThrown )
            {
                throw new AssertFailedException(
                    String.Format("An exception of type {0} was expected, but not thrown", typeof(T))
                    );
            }
        }
    }
}

즉, 단위 테스트는 다음과 같습니다.

[TestMethod()]
public void ExceptionTest()
{
    String testStr = null;
    MyAssert.Throws<NullReferenceException>(() => testStr.ToUpper());
}

나머지 단위 테스트 구문과 비슷하게 보이고 동작합니다.

원래 MSTEST를 사용하는 경우 원래는 ExpectedException 속성, 당신은 이것을 할 수 있습니다 :

try 
{
    SomeExceptionThrowingMethod()
    Assert.Fail("no exception thrown");
}
catch (Exception ex)
{
    Assert.IsTrue(ex is SpecificExceptionType);
}

Nunit을 사용하는 경우 다음과 같은 작업을 수행 할 수 있습니다.

Assert.Throws<ExpectedException>(() => methodToTest());


더 검증하기 위해 던진 예외를 저장할 수도 있습니다.

ExpectedException ex = Assert.Throws<ExpectedException>(() => methodToTest());
Assert.AreEqual( "Expected message text.", ex.Message );
Assert.AreEqual( 5, ex.SomeNumber);

보다: http://nunit.org/docs/2.5/exceptionAsserts.html

여기에 시연 된 바와 같이 몇 가지 함정으로 이어질 수 있으므로 expectionException을 사용하는 데주의하십시오.

http://geekswithblogs.net/sdorman/archive/2009/01/17/unit-testing-and-expected-exceptions.aspx

그리고 여기:

http://xunit.github.io/docs/comparisons.html

예외를 테스트 해야하는 경우, 길에 덜 찌그러져 있습니다. try {act/fail} catch {assert} 메소드를 사용할 수 있으며, 이는 예상 외환 이외의 예외 테스트를 직접 지원하지 않는 프레임 워크에 유용 할 수 있습니다.

더 나은 대안은 xunit.net을 사용하는 것입니다. xunit.net은 다른 모든 실수로부터 배웠고 개선 된 매우 현대적이고 미래 지향적이며 확장 가능한 단위 테스트 프레임 워크를 사용하는 것입니다. 그러한 개선은 Assert.throws이며, 이는 예외를 주장하는 데 훨씬 더 나은 구문을 제공합니다.

github에서 xunit.net을 찾을 수 있습니다. http://xunit.github.io/

프로젝트에서 작업중 인 프로젝트에는이 작업을 수행하는 또 다른 솔루션이 있습니다.

먼저 예외 호출이 예외를 일으킨 메소드 호출을 고려하여 예상 exceptionAttribute가 마음에 들지 않습니다.

대신 헬퍼 메드 로이 작업을 수행합니다.

테스트

[TestMethod]
public void AccountRepository_ThrowsExceptionIfFileisCorrupt()
{
     var file = File.Create("Accounts.bin");
     file.WriteByte(1);
     file.Close();

     IAccountRepository repo = new FileAccountRepository();
     TestHelpers.AssertThrows<SerializationException>(()=>repo.GetAll());            
}

헬퍼 메드

public static TException AssertThrows<TException>(Action action) where TException : Exception
    {
        try
        {
            action();
        }
        catch (TException ex)
        {
            return ex;
        }
        Assert.Fail("Expected exception was not thrown");

        return null;
    }

깔끔하지 않아;)

MStest (v2)는 이제 다음과 같이 사용할 수있는 assert.throwsexception 함수를 가지고 있습니다.

Assert.ThrowsException<System.FormatException>(() =>
            {
                Story actual = PersonalSite.Services.Content.ExtractHeader(String.Empty);
            }); 

Nuget으로 설치할 수 있습니다. Install-Package MSTest.TestFramework

테스트 방법의 속성입니다 ... Assert를 사용하지 않습니다. 이렇게 보인다 :

[ExpectedException(typeof(ExceptionType))]
public void YourMethod_should_throw_exception()

다음을 사용하여 Nuget에서 패키지를 다운로드 할 수 있습니다. PM> 설치 패키지 mstestextensions 추가합니다 assert.throws () NUNIT/XUNIT에서 MSTEST 스타일의 구문.

높은 수준의 지침 : 어셈블리를 다운로드하고 베이스 테스트 그리고 당신은 그것을 사용할 수 있습니다 assert.throws () 통사론.

Throws 구현의 주요 방법은 다음과 같이 보입니다.

public static void Throws<T>(Action task, string expectedMessage, ExceptionMessageCompareOptions options) where T : Exception
{
    try
    {
        task();
    }
    catch (Exception ex)
    {
        AssertExceptionType<T>(ex);
        AssertExceptionMessage(ex, expectedMessage, options);
        return;
    }

    if (typeof(T).Equals(new Exception().GetType()))
    {
        Assert.Fail("Expected exception but no exception was thrown.");
    }
    else
    {
        Assert.Fail(string.Format("Expected exception of type {0} but no exception was thrown.", typeof(T)));
    }
}

공개 :이 패키지를 모았습니다.

더 많은 정보: http://www.bradoncode.com/blog/2012/01/asserting-exceptions-in-mstest-with.html

간단한 한 줄로 이것을 달성 할 수 있습니다.

당신의 수술이라면 foo.bar() 비동기 :

await Assert.ThrowsExceptionAsync<Exception>(() => foo.bar());

만약에 foo.bar() 비동기가 아닙니다

Assert.ThrowsException<Exception>(() => foo.bar());

나는 ExpectedException 속성을 사용하거나(너무 제한적이고 오류가 발생하기 쉬움) 각 테스트에 try/catch 블록을 작성하는 것을 권장하지 않습니다(너무 복잡하고 오류가 발생하기 쉬움).테스트 프레임워크에서 제공하거나 직접 작성하여 잘 설계된 Assert 메서드를 사용하세요.제가 작성하고 사용한 내용은 다음과 같습니다.

public static class ExceptionAssert
{
    private static T GetException<T>(Action action, string message="") where T : Exception
    {
        try
        {
            action();
        }
        catch (T exception)
        {
            return exception;
        }
        throw new AssertFailedException("Expected exception " + typeof(T).FullName + ", but none was propagated.  " + message);
    }

    public static void Propagates<T>(Action action) where T : Exception
    {
        Propagates<T>(action, "");
    }

    public static void Propagates<T>(Action action, string message) where T : Exception
    {
        GetException<T>(action, message);
    }

    public static void Propagates<T>(Action action, Action<T> validation) where T : Exception
    {
        Propagates(action, validation, "");
    }

    public static void Propagates<T>(Action action, Action<T> validation, string message) where T : Exception
    {
        validation(GetException<T>(action, message));
    }
}

사용 예:

    [TestMethod]
    public void Run_PropagatesWin32Exception_ForInvalidExeFile()
    {
        (test setup that might propagate Win32Exception)
        ExceptionAssert.Propagates<Win32Exception>(
            () => CommandExecutionUtil.Run(Assembly.GetExecutingAssembly().Location, new string[0]));
        (more asserts or something)
    }

    [TestMethod]
    public void Run_PropagatesFileNotFoundException_ForExecutableNotFound()
    {
        (test setup that might propagate FileNotFoundException)
        ExceptionAssert.Propagates<FileNotFoundException>(
            () => CommandExecutionUtil.Run("NotThere.exe", new string[0]),
            e => StringAssert.Contains(e.Message, "NotThere.exe"));
        (more asserts or something)
    }

노트

유효성 검사 콜백을 지원하는 대신 예외를 반환하는 것은 이 주장의 호출 구문이 내가 사용하는 다른 주장과 매우 ​​다르다는 점을 제외하면 합리적인 아이디어입니다.

다른 사람들과 달리 저는 예외가 호출에서 전파되는지 여부만 테스트할 수 있기 때문에 'throws' 대신 'propagates'를 사용합니다.예외가 발생하는지 직접 테스트할 수는 없습니다.하지만 이미지 던지기를 다음과 같이 의미할 수 있다고 가정합니다.던지고 잡히지 않음.

최종 생각

이런 종류의 접근 방식으로 전환하기 전에 테스트에서 예외 유형만 확인할 때 ExpectedException 특성을 사용하고 추가 검증이 필요한 경우 try/catch 블록을 사용하는 것을 고려했습니다.하지만 각 테스트에 어떤 기술을 사용할지 고민해야 할 뿐만 아니라, 필요에 따라 한 기술에서 다른 기술로 코드를 변경하는 것도 결코 쉬운 일이 아니었습니다.하나의 일관된 접근 방식을 사용하면 정신적 노력이 절약됩니다.

요약하면 이 접근 방식은 다음과 같습니다.사용 용이성, 유연성 및 견고성(잘못 사용하기 어려움)

위의 @Richiban이 제공 한 도우미는 예외가 발생하는 상황을 처리하지는 않지만 예상되는 유형이 아닌 경우를 제외하고는 훌륭하게 작동합니다. 다음은 다음과 같습니다.

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace YourProject.Tests
{
    public static class MyAssert
    {
        /// <summary>
        /// Helper for Asserting that a function throws an exception of a particular type.
        /// </summary>
        public static void Throws<T>( Action func ) where T : Exception
        {
            Exception exceptionOther = null;
            var exceptionThrown = false;
            try
            {
                func.Invoke();
            }
            catch ( T )
            {
                exceptionThrown = true;
            }
            catch (Exception e) {
                exceptionOther = e;
            }

            if ( !exceptionThrown )
            {
                if (exceptionOther != null) {
                    throw new AssertFailedException(
                        String.Format("An exception of type {0} was expected, but not thrown. Instead, an exception of type {1} was thrown.", typeof(T), exceptionOther.GetType()),
                        exceptionOther
                        );
                }

                throw new AssertFailedException(
                    String.Format("An exception of type {0} was expected, but no exception was thrown.", typeof(T))
                    );
            }
        }
    }
}

다른 테스트 클래스 사용을 언급하기 때문에 ExpectedException 속성은 사용하는 것입니다 shoudly'에스 해야 할 일.

Should.Throw<DivideByZeroException>(() => { MyDivideMethod(1, 0); });

우리에게 요구 사항이 있다고 가정 해 봅시다 고객 있어야합니다 주소 an을 만들려면 주문하다. 그렇지 않다면 CreateOrderForCustomer 방법이 발생해야합니다 ArgumentException. 그런 다음 우리는 다음을 쓸 수 있습니다.

[TestMethod]
public void NullUserIdInConstructor()
{
  var customer = new Customer(name := "Justin", address := null};

  Should.Throw<ArgumentException>(() => {
    var order = CreateOrderForCustomer(customer) });
}

이것은 An을 사용하는 것보다 낫습니다 ExpectedException 우리는 오류를 던져야 할 것에 대해 구체적이기 때문에 속성. 이를 통해 테스트의 요구 사항이 더 명확 해지고 테스트가 실패하면 진단이 더 쉬워집니다.

또한 a가 있습니다 Should.ThrowAsync 비동기 방법 테스트 용.

대안으로 테스트 예외를 시도해 볼 수 있습니다. 실제로 테스트에서 다음 2 줄로 던져집니다.

var testDelegate = () => MyService.Method(params);
Assert.Throws<Exception>(testDelegate);

글쎄, 나는 여기에 다른 모든 사람들이 전에 말한 것을 거의 요약 할 것입니다 ... 어쨌든, 여기에 좋은 답변에 따라 내가 만든 코드는 다음과 같습니다. :) 모든 일은 복사 및 사용입니다 ...

/// <summary>
/// Checks to make sure that the input delegate throws a exception of type TException.
/// </summary>
/// <typeparam name="TException">The type of exception expected.</typeparam>
/// <param name="methodToExecute">The method to execute to generate the exception.</param>
public static void AssertRaises<TException>(Action methodToExecute) where TException : System.Exception
{
    try
    {
        methodToExecute();
    }
    catch (TException) {
        return;
    }  
    catch (System.Exception ex)
    {
        Assert.Fail("Expected exception of type " + typeof(TException) + " but type of " + ex.GetType() + " was thrown instead.");
    }
    Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown.");  
}

vs 내장 단위 테스트에서 "모든 예외"가 던져 졌는지 확인하려면 유형을 알지 못하면 캐치를 모두 사용할 수 있습니다.

[TestMethod]
[ExpectedException(typeof(Exception), AllowDerivedTypes = true)]
public void ThrowExceptionTest()
{
    //...
}

체크 아웃 NUNIT 문서 예제 :

[ExpectedException( typeof( ArgumentException ) )]

이것은 어떤 테스트 프레임 워크를 사용하고 있습니까?

예를 들어, MBUNIT에서는 예상 예외를 지정하여 속성으로 예상되는 예외를 지정할 수 있습니다.

[ExpectedException(typeof(ArgumentException))]

사용하는 경우 NUNIT, 이 시도:

Assert.That(() =>
        {
            Your_Method_To_Test();
        }, Throws.TypeOf<Your_Specific_Exception>().With.Message.EqualTo("Your_Specific_Message"));

이것은 오래된 질문이지만 토론에 새로운 생각을 추가하고 싶습니다. 나는 배치, 행동, 예상, 정리, 행동, 주장을 주장했다. 예상되는 예외 포인터를 만들고 지정되었다고 주장 할 수 있습니다. 이것은 어획량 블록에서 어설 션을하는 것보다 깨끗한 느낌이 듭니다. ACT 섹션은 대부분 코드 한 줄이 테스트중인 방법을 호출하기 위해 남겨 둡니다. 당신도 그럴 필요가 없습니다 Assert.Fail(); 또는 return 코드의 여러 지점에서. 다른 예외가 발생하면 테스트가 잡히지 않기 때문에 테스트가 실패하게됩니다. 예상 유형을 제외하고는 예상 유형을 제외하고는 예상되는 유형을 제외하고는 당신이 기대했던 것이 아니었고, 메시지 또는 다른 속성에 대해 주장하는 것은 아니 었습니다. 예외는 테스트가 실수로 통과되지 않도록하는 데 도움이됩니다.

[TestMethod]
public void Bar_InvalidDependency_ThrowsInvalidOperationException()
{
    // Expectations
    InvalidOperationException expectedException = null;
    string expectedExceptionMessage = "Bar did something invalid.";

    // Arrange
    IDependency dependency = DependencyMocks.Create();
    Foo foo = new Foo(dependency);

    // Act
    try
    {
        foo.Bar();
    }
    catch (InvalidOperationException ex)
    {
        expectedException = ex;
    }

    // Assert
    Assert.IsNotNull(expectedException);
    Assert.AreEqual(expectedExceptionMessage, expectedException.Message);
}

멋진 도서관이 있습니다 nfluent 어느 어설 션 쓰기 방식을 속도와 완화시킵니다..

예외를 던지기위한 주장을 작성하는 것은 매우 간단합니다.

    [Test]
    public void given_when_then()
    {
        Check.ThatCode(() => MethodToTest())
            .Throws<Exception>()
            .WithMessage("Process has been failed");
    }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top