C# 如何使用 Assert.Throws 来断言异常的类型?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1609536/
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 19:22:05  来源:igfitidea点击:

How do I use Assert.Throws to assert the type of the exception?

c#exceptionnunitassertions

提问by epitka

How do I use Assert.Throwsto assert the type of the exception and the actual message wording.

我如何使用Assert.Throws来断言异常的类型和实际的消息措辞。

Something like this:

像这样的东西:

Assert.Throws<Exception>(
    ()=>user.MakeUserActive()).WithMessage("Actual exception message")

The method I am testing throws multiple messages of the same type, with different messages, and I need a way to test that the correct message is thrown depending on the context.

我正在测试的方法抛出多个相同类型的消息,具有不同的消息,我需要一种方法来测试根据上下文抛出正确的消息。

采纳答案by Patrik H?gne

Assert.Throwsreturns the exception that's thrown which lets you assert on the exception.

Assert.Throws返回抛出的异常,让您对异常进行断言。

var ex = Assert.Throws<Exception>(() => user.MakeUserActive());
Assert.That(ex.Message, Is.EqualTo("Actual exception message"));

So if no exception is thrown, or an exception of the wrong type is thrown, the first Assert.Throwsassertion will fail. However if an exception of the correct type is thrown then you can now assert on the actual exception that you've saved in the variable.

所以如果没有抛出异常,或者抛出了错误类型的异常,第一个Assert.Throws断言就会失败。但是,如果抛出正确类型的异常,那么您现在可以对保存在变量中的实际异常进行断言。

By using this pattern you can assert on other things than the exception message, e.g. in the case of ArgumentExceptionand derivatives, you can assert that the parameter name is correct:

通过使用此模式,您可以对异常消息以外的其他内容进行断言,例如在ArgumentException和 派生的情况下,您可以断言参数名称是正确的:

var ex = Assert.Throws<ArgumentNullException>(() => foo.Bar(null));
Assert.That(ex.ParamName, Is.EqualTo("bar"));

You can also use the fluent API for doing these asserts:

您还可以使用 fluent API 来执行这些断言:

Assert.That(() => foo.Bar(null), 
Throws.Exception
  .TypeOf<ArgumentNullException>()
  .With.Property("ParamName")
  .EqualTo("bar"));

or alternatively

或者

Assert.That(
    Assert.Throws<ArgumentNullException>(() =>
        foo.Bar(null)
    .ParamName,
Is.EqualTo("bar"));

A little tip when asserting on exception messages is to decorate the test method with the SetCultureAttributeto make sure that the thrown message is using the expected culture. This comes into play if you store your exception messages as resources to allow for localization.

对异常消息进行断言时的一个小技巧是用 装饰测试方法以SetCultureAttribute确保抛出的消息使用预期的文化。如果您将异常消息存储为资源以允许本地化,这就会发挥作用。

回答by Hymanson Pope

You can now use the ExpectedExceptionattributes, e.g.

您现在可以使用ExpectedException属性,例如

[Test]
[ExpectedException(typeof(InvalidOperationException), 
 ExpectedMessage="You can't do that!"]
public void MethodA_WithNull_ThrowsInvalidOperationException()
{
    MethodA(null);
}

回答by persistent

It's a long time since this issue was raised, I realize, but I recently ran into the same thing, and suggest this function for MSTest:

自从这个问题被提出以来已经很长时间了,我意识到,但我最近遇到了同样的事情,并为 MSTest 建议了这个功能:

public bool AssertThrows(Action action) where T : Exception 
{ 
try {action();} 
catch(Exception exception) 
{ 
    if (exception.GetType() == typeof(T)) return true; 
} 
return false; 
}

usage:

用法:

Assert.IsTrue(AssertThrows<FormatException>(delegate{ newMyMethod(MyParameter); }));

More here: http://phejndorf.wordpress.com/2011/02/21/assert-that-a-particular-exception-has-occured/

更多信息:http: //phejndorf.wordpress.com/2011/02/21/assert-that-a-particular-exception-has-occured/

回答by fre0n

To expand on persistent's answer, and to provide more of the functionality of NUnit, you can do this:

为了扩展persistent的答案,并提供更多的NUnit功能,你可以这样做:

public bool AssertThrows<TException>(
    Action action,
    Func<TException, bool> exceptionCondition = null)
    where TException : Exception 
{
    try
    {
        action();
    }
    catch (TException ex)
    {
        if (exceptionCondition != null)
        {
            return exceptionCondition(ex);
        }

        return true;
    }
    catch
    {
        return false;
    }

    return false; 
}

Examples:

例子:

// No exception thrown - test fails.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => {}));

// Wrong exception thrown - test fails.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => { throw new ApplicationException(); }));

// Correct exception thrown - test passes.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => { throw new InvalidOperationException(); }));

// Correct exception thrown, but wrong message - test fails.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => { throw new InvalidOperationException("ABCD"); },
        ex => ex.Message == "1234"));

// Correct exception thrown, with correct message - test passes.
Assert.IsTrue(
    AssertThrows<InvalidOperationException>(
        () => { throw new InvalidOperationException("1234"); },
        ex => ex.Message == "1234"));

回答by Jordan Morris

Assert.That(myTestDelegate, Throws.ArgumentException
    .With.Property("Message").EqualTo("your argument is invalid."));

回答by Savage

Since I'm disturbed by the verbosity of some of the new NUnit patterns, I use something like this to create code that is cleaner for me personally:

由于我对一些新的 NUnit 模式的冗长感到不安,我使用这样的东西来创建对我个人来说更清晰的代码:

public void AssertBusinessRuleException(TestDelegate code, string expectedMessage)
{
    var ex = Assert.Throws<BusinessRuleException>(code);
    Assert.AreEqual(ex.Message, expectedMessage);
}

public void AssertException<T>(TestDelegate code, string expectedMessage) where T:Exception
{
    var ex = Assert.Throws<T>(code);
    Assert.AreEqual(ex.Message, expectedMessage);
}

The usage is then:

用法是:

AssertBusinessRuleException(() => user.MakeUserActive(), "Actual exception message");

回答by Tvde1

This is an old yet relevant question with outdated answers so I'm adding the current solution:

这是一个古老但相关的问题,答案已经过时,所以我添加了当前的解决方案:

public void Test() {
    throw new MyCustomException("You can't do that!");
}

[TestMethod]
public void ThisWillPassIfExceptionThrown()
{
    var exception = Assert.ThrowsException<MyCustomException>(
        () => Test(),
        "This should have thrown!");
    Assert.AreEqual("You can't do that!", exception.Message);
}

This works with using Microsoft.VisualStudio.TestTools.UnitTesting;

这适用于 using Microsoft.VisualStudio.TestTools.UnitTesting;