Elegant Way to Verify That Method Throws Exception in .NET
From time to time, we face a situation when we need to define a variable that points to a method or an anonymous function. It could be a part of business logic or some test case from unit tests. C# has a particular type that allows pointing to a specific method with a particular list of parameters and return type. Instead of defining a new delegate type, C # contains build-in generic delegates such as Action and Func.
All code you can find in the repository.
Commonly used practice to validate input model with some business rules requires us to throw validation exception to indicate that model is invalid because input parameters are wrong.
Basic Validator
Let`s define the simplest business case that we accept input model with first name and name should not be null or empty. If the name violates the rule, we need to throw ValidationException.
Take a look at the input model:
1 | class InputModel { |
It`s a good tone to define our own exception classes:
1 | public class ValidationException : Exception |
And the main player in this article, Validator with validation logic:
1 | public class Validator |
How to cover exception with unit tests
Our test project utilizes NUnit as a test framework and FluentAssetrtions to make assertions clean and easily readable.
Let`s take a look at how we should cover such validation logic with unit tests.
At first, we will cover success flow when the model is valid. We need to be sure that no exception was thrown.
1 | [ ] |
In the example above, we define action validate
and verify that this action doesn`t throw an exception during execution.
To verify that action throws exception, we do it in the same way:
1 | [ ] |
Generic method Throw<T>(string message) helps to verify that exception has required type and exception message equals predefined expected exception message.
If we work with async methods, we need to change Action to Func<T>.
Take a look at the difference between Action and Func.
Async version of same tests looks like:
1 | [ ] |
Conclusion
We always should verify all business logic in unit tests, and exceptions are part of business logic. As you see, it is pretty simple to test that method throws an exception, and it doesn`t matter method is synchronous or asynchronous.