我如何使用Assert(或其他测试类)来验证在使用MSTest/Microsoft.VisualStudio.TestTools.UnitTesting时抛出了异常?


当前回答

通常你的测试框架会给出答案。但如果它不够灵活,你可以这样做:

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
}

如果绝对必须捕获Exception,则需要重新抛出Assert.Fail()。但实际上,这是一个你不应该手写的信号;检查测试框架中的选项,或者查看是否可以抛出更有意义的异常进行测试。

catch (AssertionException) { throw; }

您应该能够根据自己的需要调整这种方法——包括指定要捕获的异常类型。如果你只期望某些类型,完成catch块:

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

其他回答

我知道这个帖子很老了,有很多很好的答案,但值得一提的是,局部函数可以以一种非常简单的方式提供帮助。

//Arrange

//Act
void LocalFunction() => mr.ActualMethod(params);

//Assert
Assert.Throws<Exception>(LocalFunction);

在VS内置单元测试中,如果你只是想验证抛出了“任何异常”,但你不知道类型,你可以使用catch all:

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

Even though this is an old question, I would like to add a new thought to the discussion. I have extended the Arrange, Act, Assert pattern to be Expected, Arrange, Act, Assert. You can make an expected exception pointer, then assert it was assigned to. This feels cleaner than doing your Asserts in a catch block, leaving your Act section mostly just for the one line of code to call the method under test. You also don't have to Assert.Fail(); or return from multiple points in the code. Any other exception thrown will cause the test to fail, because it won't be caught, and if an exception of your expected type is thrown, but the it wasn't the one you were expecting, Asserting against the message or other properties of the exception help make sure your test won't pass inadvertently.

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

这取决于您使用的测试框架?

例如,在MbUnit中,您可以用一个属性指定预期的异常,以确保您得到的是真正预期的异常。

[ExpectedException(typeof(ArgumentException))]

通常你的测试框架会给出答案。但如果它不够灵活,你可以这样做:

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
}

如果绝对必须捕获Exception,则需要重新抛出Assert.Fail()。但实际上,这是一个你不应该手写的信号;检查测试框架中的选项,或者查看是否可以抛出更有意义的异常进行测试。

catch (AssertionException) { throw; }

您应该能够根据自己的需要调整这种方法——包括指定要捕获的异常类型。如果你只期望某些类型,完成catch块:

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