How do I use Assert to verify that an exception ha

2019-01-03 19:20发布

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

21条回答
在下西门庆
2楼-- · 2019-01-03 19:38

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:

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.

查看更多
The star\"
3楼-- · 2019-01-03 19:39

As an alternative you can try testing exceptions are in fact being thrown with the next 2 lines in your test.

var testDelegate = () => MyService.Method(params);
Assert.Throws<Exception>(testDelegate);
查看更多
霸刀☆藐视天下
4楼-- · 2019-01-03 19:41

Since you mention using other test classes, a better option than the ExpectedException attribute is to use Shoudly's Should.Throw.

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

Let's say we have a requirement that the customer must have an address to create an order. If not, the CreateOrderForCustomer method should result in an ArgumentException. Then we could write:

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

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

This is better than using an ExpectedException attribute because we are being specific about what should throw the error. This makes requirements in our tests clearer and also makes diagnosis easier when the test fails.

Note there is also a Should.ThrowAsync for asynchronous method testing.

查看更多
ら.Afraid
5楼-- · 2019-01-03 19:42

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

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

And here:

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.

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.

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

查看更多
兄弟一词,经得起流年.
6楼-- · 2019-01-03 19:42

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.

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

查看更多
兄弟一词,经得起流年.
7楼-- · 2019-01-03 19:45

Check out nUnit Docs for examples about:

[ExpectedException( typeof( ArgumentException ) )]
查看更多
登录 后发表回答