In this article, I’ll propose a C# solution to a common testing problem with enums using a special NUnit attribute. I’ll also introduce you to a related attribute which can expand your tests.
Recently I wrote some thoughts on code coverage. In that article, I discussed a method that switched over enum values to return a string and how the method will break if the enum expands. That article got me thinking about how we should be testing things like enums.
Let me walk you through my solution.
The Problem
To do a quick recap of my prior article, the problem is if you have a switch statement like the following:
In this case, if we ever add a new enum value, that enum will return “ow” by default. That might be fine for a game project, but imagine a scenario where you needed to display a user-facing string in a business application.
Even if we had the application throw a new error on the default case, there’s no way to conclusively ensure that the method actually gets tested during development and testing before being released to production.
Since I’m all about making it impossible for various types of defects to ever exist, let’s look at my current preferred solution for this.
NUnit Values to the Rescue
The NUnit testing framework is currently my preferred unit test library for C# development. XUnit is close behind, but I find NUnit’s attribute naming more intuitive and it offers some capabilities that XUnit does not.
One of those capabilities is the use of a Values
attribute. This is an attribute that can be used to decorate a test method like so:
This code result in 3 different tests at time of execution – one that uses an input
of 1
, then another for 2
, and finally one for 3
. While I would tend to use TestCase
attributes for this specific scenario, this example should tell you a little bit about the Values
attribute in NUnit.
What’s really cool about Values
is that you can apply it to enums. Take a look at this code:
This unit test will run once for every member defined in DamageType
and pass that value in as input
.
Put another way – if we ever add a new DamageType
, the test will automatically gain a new test and verify its behavior. While this might not look like much, it helps ensure that unexpected errors are not occurring with new enum values.
I actually put this type of technique to use today in my day job on two large enums and was able to find a number of failing cases that we had no idea were even lurking deep in the code. Not only did adopting Value
attributes help prevent future bugs, but it exposed current bugs we didn’t even know we had!
But Wait, There’s More!
While I’m not sure why you’d ever want to do this, the Values
attribute can be applied to boolean
parameters, allowing NUnit to automatically inject both true and false values. Personally, I’d rather use explicit TestCase
attributes for readability, but this is something you can do if you want to.
More practically, NUnit offers a Range
attribute which works similarly to the Values
attribute, but generates a range of possible values.
Let’s say you wanted to test some percentage math:
Here, the Range
attribute lets us define an inclusive range from a low value to a high value. This will then pass in all integers between 0 and 100 to this test method as percentWhole
on a unique unit test variant.
This specific example might be good for finding boundary issues at 0 or 100, or for exposing issues with various areas on rounding around 33% or 66%.
Conclusion
Hopefully I’ve convinced you that Values
and potentially Range
are worth investigating if you’re doing .NET unit testing.
While I should caution you that if you have a large number of unit tests, you’re paying for the overhead of NUnit jumping from one test to another. In most projects and scales this won’t be an issue, but if you habitually use Range
and Values
attributes, you could get to some large sizes fairly quickly.
The range-based technique is now my preferred and standard way of testing enums going forward, because it helps mitigate the risk that I’ll forget to test something.
What other testing techniques have you investigated and enjoyed?
The post Future-proofing .NET Tests with NUnit Values Attributes appeared first on Kill All Defects.
Top comments (2)
You can solve the same problem with xUnit like this:
programmingcrumbs.blogspot.com/201...
Not as elegant, but worth doing.
Absolutely. XUnit is fantastic but a bit more opinionated than NUnit. I find NUnit to be a good choice for teaching and readability.