In the last post, you learned the basics of unit testing in .NET: you should understand the intent behind unit testing, you should have a vague idea of what unit tests should look like, and you should have looked at some of the unit testing API options that are available to you. For the remainder of this series, I’ll be focusing specifically on unit testing with NUnit and TestDriven.NET. If you have chosen to use a different API or tool, you may need to translate the code samples and steps below to match. If you don’t already have NUnit downloaded and installed, do so now.
Adding NUnit To An Existing Project
For now, we’ll assume that we are adding unit tests for a project that has already been created. We’ll deal with test-driven development (not to be confused with the test-running tool by the same name) in a future post. Our tests will be built around an example taken from the NUnit Quick Start, where we have a simple bank API that includes a single Account class. Here’s the code for the class:
Create a new project in Visual Studio named ‘NunitDemo’, add this class to it, and verify that your project builds correctly. If all goes well, you are now ready to add NUnit to the project. Assuming you are using Visual Studio, find the "References" folder under the project in the "Solution Explorer" pane. Right-click on "References" and choose "Add Reference". From the .NET tab of the "Add Reference" dialog, choose "nunit.framework", then click "Ok". This DLL contains the attributes and assertion functionality that you need to create your actual unit tests. At this point, you should see "nunit.framework" listed under the "References" folder. If so, you are now ready to begin writing test cases!
Sidetrack – Where Do Unit Tests Go?
Before we actually start writing test cases, let’s talk about where we’re going to put them. The conventional approach is to put test cases in a completely separate project from the code being tested. In our example, if our Account class is in a project named "BankSystem", our unit tests would go in a completely separate project called "BankSystem.Tests". I have two big problems with this approach. First, it bloats the size of your Visual Studio solution, which means it will take longer to build the solution, and you have twice the number of overhead files (the project file, the documentation file, all the little temp files and folders that Visual Studio and Resharper create, etc). Second, what if you need to test a class or method that’s marked as internal? You can’t do that if your tests live in a completely separate project.
My recommendation is to put the tests in the same project as the code being tested, but do separate the tests into their own namespaces. For example, our "Account" class is in the "NunitDemo" namespace, so its tests will go in the "NunitDemo.Tests" namesapce. The downside to this approach is that your test cases will now be distributed along with your actual API, but there’s a very easy solution to this: wrap the tests with preprocessor directives. Depending on your environment and how you deploy your production assemblies, it may be sufficient to simply test whether the DEBUG symbol is defined. This symbol is defined by default when you build a project in debug mode in Visual Studio. If you sometimes deploy debug versions of code, then you may want to define a custom symbol to use instead. For now, we’ll assume that we want our unit tests compiled if the DEBUG symbol is defined.
Writing Your First NUnit Test
At this point, your project should have a reference to nunit.framework, and you should know where you are going to put the test cases. Let’s go ahead and create a test fixture for the Account class. Within Visual Studio solution explorer, create a new folder called "Tests". Folders in Visual Studio are typically used to denote namespaces, so any classes you add to this folder will be created in the "NunitDemo.Tests" namespace by default (you can change the namespace after the fact, but that would be WRONG). Right-click on the new folder, click "Add", then select "Class". Name the class "AccountTests". Visual Studio should create the class and open the .cs file for you. This is just a standard class right now. We have to make a few changes in order for it to become a test fixture.
First, let’s wrap everything in a ‘#if DEBUG’ directive (see the code below if you aren’t sure how to do that). This insures that our new class will only be compiled if the DEBUG directive is defined. Next, add a using statement for the NUnit.Framework namespace. NUnit requires that test fixtures be public classes, so go ahead and add the ‘public’ keyword to the class definition. Finally, apply the "TestFixture" attribute to the class. You now have an empty test fixture like so:
Let’s go ahead and add our first test case. We’re going to create a test to verify that the deposit method correctly adds money to the account balance. Create a method named "Deposit_AddsValueToBalance". Yes, typically underscores in method names are BAAAD, but this isn’t a normal method, it’s a test case. When a test case fails, you want to know immediately what method failed and what the test was supposed to verify, so you need to use descriptive names. Using underscores allows you to clearly indicate the name of the method being tested and the behavior being tested. Anyway, you’ve created your method, now mark it with the "Test" attribute. Congratulations, you now have an empty test case! You could run the test now, and it would pass (because it doesn’t do anything), but let’s add some meat to it first.
Before we write the logic for the test, let’s think about exactly what we want to test: we should be able to call the Deposit method, passing in some value X, and the balance should be incremented by that same value X. How do we test that? First, we call the method, passing in some constant value. Next, we use the Assert class from NUnit to verify that the balance increased by that amount. There are two ways we could do that in NUnit: we can use the so-called "classic model", or we could use the newer "constraint-based" model. I’m still on the fence about which one I prefer, but for now, we’ll stick with the classic model, which means we’re going to use the Assert.AreEqual method to check the value of the Balance property after we have invoked the Deposit method.
That’s a long paragraph. If you’re confused, maybe this will help:
And that’s our test case. Simple, isn’t it? We’re writing code to test code, utilizing the Assert class to verify that expected things are actually happening. The Assert.AreEqual call will throw an exception if for some reason the Balance property isn’t equal to 100. Assuming you are using TestDriven.NET, you can run your test by right-clicking on either the name of the test method or the name of the fixture class in the code window, then selecting "Run Tests" from the context menu. TestDriven.NET will launch in the background, run your tests, then spit out the results in the Output pane within Visual Studio.
So far, we’ve tested a single, simple method using a single method from the Assert class. Unfortunately, testing won’t always be this simple and straightforward. In the next post, we’ll begin creating more complex test cases as we try out different Assert methods. We’ll also look at some of the other attributes that NUnit supports and how they can help you create tests more efficiently.