Creating custom attributes with internal NUnit features

Today I’m going to talk about the NUnit test framework and its hidden features. Okay, maybe “hidden” is not the completely correct word for this case because nothing is hidden in the open-source world. However, the NUnit implementation has several internal features which may be useful for those who are going to use a little bit more that just standard NUnit attributes.

Challenge: to implement a custom attribute for performing some actions for each NUnit test followed after this attribute.

First of all, let’s recall the anatomy of NUnit tests. A typical class with NUnit tests looks like this:

Here we can see a couple of attributes on the class and test levels. When we start running these tests, the NUnit test adapter or console test runner (depends on where we’re going to run our tests) parse our test code and execute tests accordingly.

If we need to perform some actions before or after each test (for example, write test info to a report file), we can utilize several more attributes out-of-the-box: SetUp / TearDown applied on the method level. Actually, this is the reason why these attributes were created for. This approach is good enough if we have a single test class where all test cases need the same actions before/after them. However, this approach may not help us in case:

  • if we have several classes with tests which need more or less the same actions before/after them, i.e. we need to duplicate bodies of the SetUp / TearDown methods for each of them. It leads to the more bulky code and doesn’t improve maintainability at all;
  • if the actions we are going to perform before/after each test method assume some complex flows and a lot of code. It doesn’t improve readability and cannot be reused easily.

What we can do in this case is to create our own attribute which will be listening to NUnit test runner events and perform the required actions in time. In order to provide some value for this example, I would like to implement measuring time needed for running each test marked by our custom attribute.

Let’s create a separate class for our attribute and call it Report. Here we will do the magic:

As we see from the code above, the Report class inherits from the Attribute system class. This inheritance allows us to specify 2 important options for the usage of our attribute: AttributeTargets and AllowMultiple. The AttributeTargets option can be set to almost all entities that exist in .NET framework (assembly, class, enum, etc.) but for our case AttributeTargets.Method is the best choice. The AllowMultiple option defines whether we can use our attribute more than once for a specific method or not. Based on the purpose of our attribute, we disable multiple usages.

In order to get access to the NUnit test run process and listen to different test events we also need to implement the ITestAction interface in the Report class (I recommend to use the Visual Studio IntelliSence for this purpose):

Implementing the ITestAction interface obliges us to implement also its methods and properties. As we see from the code above, there are two methods (BeforeTest and AfterTest) and one Targets property. The purpose of the BeforeTest and AfterTest methods is obvious – to execute sets of actions before and after the target specified by the Targets property.

Unlike AttributeTargets option that we’ve set above, the Targets property defines what’s going to be affected by the [Report] attribute. In the other words, the Targets property defines before or after which entity the self-titled methods will be called.

Note: the BeforeTest and AfterTest methods take the same single parameter – an object of the ITest interface. In a nutshell, this object allows us to get access to different test properties. But this is a different topic which I’m going to explain in future articles.

 

As I’ve already mentioned, the purpose of the [Report] attribute is to show how much time a separate test marked by this attribute takes. As an example, I am going to use the Stopwatch class from the System.Diagnostics namespace for measuring that time. Eventually, my code should look like:

I declared the private timer object of the StopWatch class which is used for measuring a time of a test run. The Report() constructor initializes a new timer every time we call it (every time we specify the [Report] attribute for a test method). The BeforeTest() method contains the only one action – start our timer before a test method is called. The AfterTest() method stops the timer and writes measured time to the console.

Now let’s go back to the initial class with tests where we can use just created [Report] attribute. I added some random delays to each test in order to vary their execution time:

Please note that we can use our [Report] attribute either separately or combine it with the [Test] attribute. After we run these tests and check the output for each of them, it looks like:

Summary:

That was just a very simple example of what we can do with ITestAction interface and its features. You can play with it, experiment and find your own usage of this cool internal feature of the NUnit. Have fun!

Like this post?

Subscribe to updates from my blog, if you don't want to miss more interesting future posts and materials

Please check your email and confirm subscription

Pin It on Pinterest

Share This