Help your Colleagues Save Time by Using NUnit Attributes in your Tests
Use NUnit Test Attributes to Generate Method Input
Let’s face it, there is nothing worse than trying to understand the code you wrote 3 months ago. Well, to be honest, trying to understand the test code you wrote 3 months ago is worse.
And the worst of the worst - is when your colleagues try to understand the test code you wrote 3 months ago.
I really feel awkward when this happens, especially because I respect their time - which is the most expensive thing that any of us own.
In this article, I am going to take you through 5 ways of using the NUnit Test Framework to simplify your test code and make it more readable. I am going to focus only on the input to your Unit Tests and not the test itself or the correct way to name your tests.
A Simple Test to Begin With

The Class1
implements a TrueOnEvenNumbers
check. You can see the repetition with multiple Asserts which is completely unnecessary. It’s worse when something like this is done in a loop inside the test method.
Having a single assertion per test makes it easier to understand and maintain the test code. Let’s use the NUnit TestCase
attribute to do just that.
1. The TestCase Attribute

NUnit is going to run the test once per theTestCase
attribute. The refactored test method now takes an input and returns an output. The input is taken from the first parameter of the TestCase
attribute. The output is checked against the ExpectedResult
property of the TestCase
attribute. I love this since the test now focuses more on the logic being tested and has a single assertion.
The NUnit Test output:

The output shows the exact parameter value being passed in each time the test method is called.
The test method logic used here are:
- Even numbers return true
- Numbers that are not even numbers return false
If you think it makes more sense to separate out the logic, it can be done nicely by using the Range
attribute from NUnit.
2. The Range Attribute

Separating the test logic, I now test the result of even number inputs. A great way to do that is to use the Range
attribute that takes a ‘from’, a ‘to’ and a ‘step’ value.
In this example I want the input to be 40, 42, 44 and 46 and therefore I use a Range(40, 46, 2)
that starts ‘from’ 40, go ‘to’ 46, and increments at each ‘step’ by 2. Notice how the Range
attribute is used on the input parameter and not on the test method.
The output:

And the test for odd numbers would look like the following:

Wait, what is that Should().BeFalse()
syntax?!
Well, that is another way to make your tests more readable. The wonderful FluentAssertions Extensions allow for such fluent syntax during assertion: https://fluentassertions.com/introduction
3. The TestCaseSource Attribute
The TestCase attribute that we used allows us to also use Enumerations:

For a given workday, test that the mood one is in matches the expected value. Notice the return type of the GetMoodWithReasonForWorkday
method:

It is not the enumeration Mood
but the type MoodWithReason
:

I would like to test both the properties of the struct MoodWithReason
and would like to use it as the ExpectedResult
property in the TestCase
attribute like this:

But that leads to the following compilation error:

Well have no fear, the TestCaseSource
attribute is here:

The TestCaseSource
attribute allows us to define any number and type of input (including expected results) and use it as input to our test methods. The iterator MoodWithReasons
(with an ‘s’ at the end) is defined as followed:

We can yield any number of TestCaseData
items from the iterator. The TestCaseData
type can take any number of parameters. We return two values for the two input parameters of our test method (Workday workday, MoodWithReason moodWithReason)
. Unfortunately, the output of running the tests with our generated parameters look like this:

The second parameter is of type MoodWithReason
and does not show the actual values used during the test. To see the actual parameters passed in, a different TestCaseSource
can be used:

The corresponding Test Method now takes three input parameters:

And the corresponding Test Output shows all input parameter values:

4. The Values Attribute
The Values
attribute creates a combination of each possible input value. Let’s see what that means:

Here the Values
attributes are used on the parameters of type Mood
and Reason
, each being an enumeration:

Running the test lead to a total of 10 test method calls:

As you can see NUnit generates a test for each possible combination of the two input parameter types!! How cool is that?
There are a few Test Method level attributes that can be used together with the Values
attribute for specific purposes. A list of all the NUnit attributes can be found at:
https://docs.nunit.org/articles/nunit/writing-tests/attributes.html
5. The ValueSource Attribute
Just like the TestCaseSource
attribute, there is a ValueSource
attribute.

Using the Values
attribute you could write a test to check that any multiplication of the firstValue
and the secondValue
always gives a value of less than 10000. Another way to do that would be to use the ValueSource
attribute:

And the parameter sources for the test, FirstValueSource
and SecondValueSource
, can be defined as:

And the corresponding Test Method output is as follows:

There are a lot of other useful NUnit attributes for varying purposes. I have found the ones I described to be the most helpful.
All code used in this article can be found in my GitHub repository.
I hope that my article helps others.