Last active
January 4, 2016 02:27
-
-
Save danielrbradley/6671613 to your computer and use it in GitHub Desktop.
Custom Throws assert for the NUnit framework for handling async code.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace NUnit.Framework | |
{ | |
using System; | |
using System.Threading.Tasks; | |
using NUnit.Framework; | |
public static class AsyncAsserts | |
{ | |
/// <summary> | |
/// Assert that an async method fails due to a specific exception. | |
/// This exception can be thrown directly or be the root cause of an aggregate exception. | |
/// </summary> | |
/// <typeparam name="T">Exception type expected</typeparam> | |
/// <param name="testCode">Test async delegate</param> | |
public static void Throws<T>(Func<Task> testCode) | |
where T : Exception | |
{ | |
try | |
{ | |
Task.WaitAll(testCode()); | |
Assert.Fail("Expected exception of type: {0}", typeof(T)); | |
} | |
catch (AggregateException aex) | |
{ | |
if (!aex.BaseIsOfType<T>()) | |
{ | |
Assert.Fail( | |
"Expected aggregate exception with base type: {0}" | |
+ "\r\nBut got an aggregate exception with base type: {1}", | |
typeof(T), | |
aex.GetBaseException().GetType()); | |
} | |
// Continue excecution if base exception was expected. | |
} | |
catch (T) | |
{ | |
// Swallow exception as this is correct. | |
} | |
} | |
} | |
public static class AggregateExceptionExtensions | |
{ | |
public static bool BaseIsOfType<T>(this AggregateException aex) | |
{ | |
return aex.GetBaseException() is T; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Tests | |
{ | |
using NUnit.Framework; | |
// Example AsyncAsserts.Throws<T>(testCode) usage. | |
[Category("Integration")] | |
public class CreateTest | |
{ | |
[Test] | |
public void ArgumentException() | |
{ | |
AsyncAsserts.Throws<ArgumentException>( | |
() => Service.Create("")); | |
} | |
} | |
} |
Even better, return the exception so that properties like .Message
can be inspected:
public static async Task<T> ThrowsAsync<T>(Func<Task> asyncDelegate) where T : Exception
{
T caughtException = null;
try
{
await asyncDelegate();
Assert.Fail("Expected exception of type: {0}", typeof(T));
}
catch (T expectedException)
{
caughtException = expectedException;
}
catch (AssertionException)
{
throw;
}
catch (Exception ex)
{
Assert.Fail("Expected exception of type: {0} but was: {1}", typeof(T), ex);
}
return caughtException;
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I would do it this way:
And usage is:
This way there is no need to play with aggregated exceptions so the result is exactly the same as in the production code (where you probably use await).