Ads by The Lounge
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.
Unit testing is only enjoyable and productive with the right toolset. NUnit is the foundation of this toolset. It is a unit testing framework for any .NET language.
NUnit leverages Reflection and Attributes to dynamically discover and execute your tests. The structure of a NUnit unit test is as follows.
Imports NUnit.Framework
<TestFixture()> _
Public Class DemoTests
<Test()> _
Public Sub TestGetIntegerFromConfigFile()
'Some code that tests the desired functionality
End Sub
End Class
You add the TextFixture attribute to notify NUnit that a class is a suite of tests. You add the Test attribute to mark a method as a single test case. You can have as many tests in a given test fixture as you want and as many test fixtures in a project as you want. The class that is the TestFixture has to be public and have a default constructor so that NUnit can use reflection to dynamically instantiate it. The methods decorated with the Test attribute have to be public, not take any arguments and return no values (Sub in VB.NET and void in C#) for the same reason.
The next step is to write the code that tests the desired functionality. It’s best if the tests are fairly straight forward and simple.
Dim demo As VBDemo.Demo = New VBDemo.Demo
Dim result As Integer = _
demo.GetFromConfigFile("MyValue", 0)
Assert.AreEqual(1, result)
Assert.AreEqual is the really crucial bit of code from this test. This is one of several types of assertions. An exception of type NUnit.Framework.AssertionException is thrown if one of the assertions fails.
Assert.AreEqual(value a, value b)
Tests if b is equal to the expected value a
Assert.AreSame(reference a, reference b)
Tests if two references point to the same object in memory
Assert.IsFalse(Boolean)
Tests if the Boolean is False
Assert.IsTrue(Boolean)
Tests if the Boolean is True
Assert.IsNull(reference)
Tests if reference is Null as expected
Assert.IsNotNull(reference)
Tests if reference is something as expected
More complex tests can be accomplished with normal if statements and the Assert.Fail method.
If (Not SomeReallyComplexStatement) Then
Assert.Fail()
End If
The code that this test exercises takes the name of a configuration setting and a default value. It will return the value from the configuration file or the default value. The test above assumes that the configuration file has a value as follows.
<configuration>
<appSettings>
<add key="MyValue" value="1" />
</appSettings>
</configuration>
A small thing that I’ve discovered is that it’s helpful in cases where there is a config file that the tests are in a console application because VS.NET will manage the app.config automatically for you. In addition, if your tests are in a console application, they could be self sustaining and run whether someone has a NUnit test runner, like NUnit GUI, installed or not. You would have to call the tests from the Main of your console application. You know that the test failed when if there is a NUnit.Framework.AssertionException thrown. I have found that this is helpful in a “Clean” environment where developer tools are not allowed.
If the code is as follows.
Public Class Demo
Public Function GetFromConfigFile( _
ByVal settingName As String, _
ByVal defaultValue As Integer) As Integer
Return defaultValue
End Function
And you run the test; the result will be as follows.
This is expected. Now you need to fix the code so that it will not result in a red bar.
Now modify the function as follows.
Try
Dim reader As System.Configuration.AppSettingsReader = _
New System.Configuration.AppSettingsReader
Dim resultAsObject As Object = _
reader.GetValue(settingName, GetType(Integer))
Int32.Parse(resultAsObject.ToString)
Return result
Catch ex As System.InvalidOperationException
'Either the value didn't exist or it was not an Int32
'Fall through to the default value below
End Try
Once it is, you are rewarded with a green bar as follows.
Since the normal path is working, you need to test the alternative paths as follows.
There are a number of alternative paths that we can investigate. You can pass in garbage, Nothing (or null in C#), the name of an item that’s not an integer and so on. You could decorate the method with an additional attribute, ExpectedException, if we expected this code to throw an exception rather than handle all of its exceptions. For this example, you simply need the non existent config value and the non integer config value cases.
Public Sub TestGetIntegerFromConfigFileNonExistant()
demo.GetFromConfigFile("MyNonExistantValue", 0)
Assert.AreEqual(0, result)
Public Sub TestGetIntegerFromConfigFileNotAnInt()
demo.GetFromConfigFile("MyNotAnIntValue", 0)
Now you have a well tested function and tests that can be run over and over again.
We have covered the basics of setting up a unit test with NUnit. There are more features that we will cover in a future post. These include the ability to specify setup and teardown methods, categories of tests and suites of tests.
The code for this post can be downloaded below. It does require NUnit.