

Testing Exceptions with xUnit and Actions
source link: https://ardalis.com/testing-exceptions-with-xunit-and-actions/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Testing Exceptions with xUnit and Actions
Date Published: 14 April 2021
When you're writing unit tests for a method, it's a good idea to test various failure conditions ("sad paths") in addition to testing the expected, everything is working condition ("happy path"). In particular, if you have a method that may throw exceptions, especially if they're custom domain exceptions, you should be sure you're testing this behavior. Another common source of exceptions is guard clauses, which are used to keep your method clean while ensuring its inputs adhere to the method's expectations.
Unlike NUnit, which mainly uses attributes for expected exceptions, and MSTest, which has little built-in support at all, xUnit provides an Assert.Throws<T>
method that is used to test for expected exceptions (NUnit 3 also has a similar method). A simple example looks like this:
Customer customer = null;
Assert.Throws<NullReferenceException>(() => customer.LastName);
In addition to this simple usage, the method also returns the captured exception, so you can make additional assertions about the message or other properties of the exception:
var customer = new Customer();
var caughtException = Assert.Throws<NameRequiredException>(() => customer.UpdateName("", ""));
Assert.Equal("A valid name must be supplied.", caughtException.Message);
Arrange, Act, Assert and Exceptions
Many tests use the Arrange, Act, Assert, or AAA testing pattern. Using this approach, tests generally have this form:
public class Customer_UpdateName
{
[Fact]
public void ThrowsExceptionGivenInvalidName
{
// Arrange
// Act
// Assert
}
}
Note: Tests should be named to that when they fail, the combination of their class name and method name clearly indicates the expectation that was not met. Read more about unit test naming conventions.
Let's fill in the details from the Customer.UpdateName()
test example, using the AAA template:
public class Customer_UpdateName
{
[Fact]
public void ThrowsExceptionGivenInvalidName
{
// Arrange
var customer = new Customer();
// Act
var caughtException = Assert.Throws<NameRequiredException>(() => customer.UpdateName("", ""));
// Assert
Assert.Equal("A valid name must be supplied.", caughtException.Message);
}
}
Do you see the problem? The Assert.Throws
line is both the Act step as well as one of the assertions. This makes the line both overly long and makes the test harder to read. We can fix this by using an Action
to represent the operation that is expected to throw an exception.
Using Actions with Assert.Throws
To help follow the AAA test pattern, represent the operation that is expected to throw an exception as a variable by using an Action
:
public class Customer_UpdateName
{
[Fact]
public void ThrowsExceptionGivenInvalidName
{
// Arrange
var customer = new Customer();
// Act
Action action = () => customer.UpdateName("", "");
// Assert
var caughtException = Assert.Throws<NameRequiredException>(action);
Assert.Equal("A valid name must be supplied.", caughtException.Message);
}
}
Now in this example, the action that is the heart of the test stands alone within the Act section of the test, and the Assert.Throws
line is much shorter and easier to follow.
FluentAssertions
If you're using FluentAssertions instead of the built-in assertions of your testing library, you would do this:
[Fact]
public void ThrowsExceptionGivenInvalidName
{
// Arrange
var customer = new Customer();
// Act
Action action = () => customer.UpdateName("", "");
// Assert
action.Should()
.Throw<NameRequiredException>()
.WithMessage("A valid name must be supplied.");
}
}
Thanks to @volkmarrigo for this suggestion!
I've been using the Action
approach recently, since my friend Shady Nagy (you should follow him on Twitter) pointed it out to me on a project we were working on together. This pattern is really simple to implement but I've found it makes tests for exceptions much cleaner.

About Ardalis
Software Architect
Steve is an experienced software architect and trainer, focusing on code quality and Domain-Driven Design with .NET.
Recommend
-
35
xUnit has a quirky system for consuming test data. Strongly typed test data can be specified with the MemberData attribute and the Theory attribute but it’s not intuitive. The MemberData...
-
11
Running xUnit.net Tests on Specific Threads for WPF and Other UI Tests
-
8
About xUnit.net xUnit.net is a free, open source, community-focused unit testing tool for the .NET Framework. Written by the original inventor of NUnit v2, xUnit.net is the latest technology for unit testing C#, F#, VB.NET...
-
7
Testing Integration Testing with xUnit Jimmy Bogard...
-
19
Unit Testing Using XUnit And MOQ In ASP.NET Core Writing unit tests can be difficult, time-consuming, and slow when you can't isolate the classes you want to test from the rest of the s...
-
9
Integration Testing: IHost Lifecycle with xUnit.Net I’m part of an initiative at work to analyze and ultimately improve our test automation practices. As part of that work, I’ll be blogging quite a bit about test automation star...
-
7
In this article, we are going to learn how to implement Unit and Integration tests on .NET using xUnit. Prerequisites Visual Studio 2022 with .NET 6 SDK Download or clone the base project from
-
10
Online TrainingNON-FUNCTIONALSTART:29 September 2021Test Automation AdvancedLEVEL: 2C# Level 2
-
10
In this article, we are going to write test cases to an Asp.NetCore Web API(.NET6) application using the xUnit.xUnit For .NET:The xUnit for .Net is a free, open-source, community-focused unit testing tool for .NET applications. By...
-
6
How to use xUnit to run unit testing in .NET and C# Published: Tuesday 2 April 2024 Software companies all over the world use unit testing to automate tests for their systems....
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK