C# 如何使用 Assert 验证是否已抛出异常?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/933613/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 03:37:45  来源:igfitidea点击:

How do I use Assert to verify that an exception has been thrown?

c#unit-testingmstestassertvs-unit-testing-framework

提问by Alex

How do I use Assert(or other Test class?) to verify that an exception has been thrown?

我如何使用Assert(或其他 Test 类?)来验证是否已抛出异常?

采纳答案by Kevin Pullin

For "Visual Studio Team Test" it appears you apply the ExpectedException attribute to the test's method.

对于“Visual Studio Team Test”,您似乎将 ExpectedException 属性应用于测试的方法。

Sample from the documentation here: A Unit Testing Walkthrough with Visual Studio Team Test

来自此处文档的示例:A Unit Testing Walkthrough with Visual Studio Team Test

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

回答by ojrac

Usually your testing framework will have an answer for this. But if it's not flexible enough, you can always do this:

通常你的测试框架会有一个答案。但如果它不够灵活,你总是可以这样做:

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

As @Jonas points out, this DOES NOT work for catching a base Exception:

正如@Jonas 指出的那样,这不适用于捕获基本异常:

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

If you absolutely must catch Exception, you need to rethrow the Assert.Fail(). But really, this is a sign you shouldn't be hand-writing this; check your test framework for options, or see if you can throw a more meaningful exception to test for.

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

catch (AssertionException) { throw; }

You should be able to adapt this approach to whatever you like -- including specifying what kinds of exceptions to catch. If you only expect certain types, finish the catchblocks off with:

您应该能够根据自己的喜好调整这种方法——包括指定要捕获的异常类型。如果您只期望某些类型,请使用以下命令完成catch块:

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

回答by bytebender

It is an attribute on the test method... you don't use Assert. Looks like this:

它是测试方法的一个属性……您不使用断言。看起来像这样:

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

回答by Jay

This is going to depend on what test framework are you using?

这将取决于您使用的是什么测试框架?

In MbUnit, for example, you can specify the expected exception with an attribute to ensure that you are getting the exception you really expect.

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

[ExpectedException(typeof(ArgumentException))]

回答by Jon Masters

Check out nUnit Docsfor examples about:

查看nUnit Docs以获取有关以下内容的示例:

[ExpectedException( typeof( ArgumentException ) )]

回答by Jon Limjap

If you're using MSTest, which originally didn't have an ExpectedExceptionattribute, you could do this:

如果您使用的是最初没有ExpectedException属性的MSTest ,您可以这样做:

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

回答by jrista

Be wary of using ExpectedException, as it can lead to several pitfalls as demonstrated here:

小心使用 ExpectedException,因为它会导致几个陷阱,如下所示:

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

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

And here:

和这里:

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

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

If you need to test for exceptions, there are less frowned upon ways. You can use the try{act/fail}catch{assert} method, which can be useful for frameworks that don't have direct support for exception tests other than ExpectedException.

如果您需要测试异常,那么不那么令人沮丧的方法。您可以使用 try{act/fail}catch{assert} 方法,该方法对于除 ExpectedException 之外不直接支持异常测试的框架非常有用。

A better alternative is to use xUnit.NET, which is a very modern, forward looking, and extensible unit testing framework that has learned from all the others mistakes, and improved. One such improvement is Assert.Throws, which provides a much better syntax for asserting exceptions.

一个更好的选择是使用 xUnit.NET,它是一个非常现代、前瞻性和可扩展的单元测试框架,它从所有其他错误中吸取了教训并进行了改进。其中一项改进是 Assert.Throws,它为断言异常提供了更好的语法。

You can find xUnit.NET at github: http://xunit.github.io/

您可以在github上找到xUnit.NET:http://xunit.github.io/

回答by Glenn

In a project i′m working on we have another solution doing this.

在我正在做的一个项目中,我们有另一个解决方案可以做到这一点。

First I don′t like the ExpectedExceptionAttribute becuase it does take in consideration which method call that caused the Exception.

首先,我不喜欢 ExpectedExceptionAttribute,因为它确实考虑了导致异常的方法调用。

I do this with a helpermethod instead.

我用一个辅助方法来做到这一点。

Test

测试

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

HelperMethod

辅助方法

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

Neat, isn′t it;)

整洁,不是吗;)

回答by Richiban

My preferred method for implementing this is to write a method called Throws, and use it just like any other Assert method. Unfortunately, .NET doesn't allow you to write a static extension method, so you can't use this method as if it actually belongs to the build in Assert class; just make another called MyAssert or something similar. The class looks like this:

我首选的实现方法是编写一个名为 Throws 的方法,并像使用任何其他 Assert 方法一样使用它。不幸的是,.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))
                    );
            }
        }
    }
}

That means that your unit test looks like this:

这意味着您的单元测试如下所示:

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

Which looks and behaves much more like the rest of your unit test syntaxes.

它的外观和行为更像单元测试语法的其余部分。

回答by roeiba

Well i'll pretty much sum up what everyone else here said before...Anyways, here's the code i built according to the good answers :) All is left to do is copy and use...

好吧,我几乎总结了这里其他人之前所说的......无论如何,这是我根据好的答案构建的代码:) 剩下要做的就是复制和使用......

/// <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.");  
}