简体   繁体   English

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

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

How do I use Assert.Throws to 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.我正在测试的方法会抛出多个相同类型的消息,但消息不同,我需要一种方法来测试是否根据上下文抛出了正确的消息。

Assert.Throws returns 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.Throws assertion will fail.所以如果没有抛出异常,或者抛出了错误类型的异常,第一个Assert.Throws断言将失败。 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.但是,如果抛出正确类型的异常,那么您现在可以对保存在变量中的实际异常进行断言。

By using this pattern you can assert on other things than the exception message, eg in the case of ArgumentException and 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 SetCultureAttribute to make sure that the thrown message is using the expected culture.对异常消息进行断言时的一个小技巧是使用SetCultureAttribute修饰测试方法,以确保抛出的消息使用预期的区域性。 This comes into play if you store your exception messages as resources to allow for localization.如果您将异常消息存储为资源以允许本地化,这就会发挥作用。

You can now use the ExpectedException attributes, eg您现在可以使用ExpectedException属性,例如

[Test]
[ExpectedException(typeof(InvalidOperationException), 
 ExpectedMessage="You can't do that!"]
public void MethodA_WithNull_ThrowsInvalidOperationException()
{
    MethodA(null);
}
Assert.That(myTestDelegate, Throws.ArgumentException
    .With.Property("Message").EqualTo("your argument is invalid."));

A solution that actually works:一个实际有效的解决方案:

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

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"));

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");

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

There is more in Assert that a particular exception has occured (Assert.Throws in MSTest) .Assert 中还有更多发生了特定异常的情况(MSTest 中的 Assert.Throws)

对于那些使用NUnit 3.0 约束模型并在此处结束的人:

Assert.That(() => MethodUnderTest(someValue), Throws.TypeOf<ArgumentException>());

Asserting exception:断言异常:

In Junit 5:在 Junit 5 中:

    @Test
    public void whenExceptionThrown_thenAssertionSucceeds() {
        Exception exception = assertThrows(NumberFormatException.class, () -> {
            Integer.parseInt("1a");
        });
    
        String expectedMessage = "For input string";
        String actualMessage = exception.getMessage();
    
        assertTrue(actualMessage.contains(expectedMessage));
    }

In Junit 4:在 Junit 4 中:

@Test(expected = NullPointerException.class)
public void whenExceptionThrown_thenExpectationSatisfied() {
    String test = null;
    test.length();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM