Caching for Non-Web Applications – Part 2

In my last blog post, entitled Caching for Non-Web Applications – Part 1 I introduced you to the MemoryCache class. This class allows you to create a cache for any type of application just like in ASP.NET applications. The great thing about the MemoryCache class is there is no reliance on the System.Web namespace. This means you are free to use the MemoryCache class in any type of application such as Windows Forms, WPF and Windows Services. The last blog post showed you how to add and retrieve data from the cache. This blog post expands on the last one and shows you additional methods you can take advantage of to work with cache data.

Add or Get Existing

The AddOrGetExisting method has the same signature as the Add method. However, instead of returning a true or false value, it will either return a null if the key/value pair was added to the cache, or returns the object if the key value is found already in the cache.

object ret;
ret = MemoryCache.Default.AddOrGetExisting("Key2", 
         "Value 2", DateTimeOffset.Now.AddSeconds(5));
if (ret == null) {
MessageBox.Show("Key did NOT exist");
}
else {
MessageBox.Show("The Key did already exist");
}

AddOrGetExisting Using CachePolicy

Just like you are able to add a new item to the cache using the CachePolicy using the Add method, you can do the same with the AddOrGetExisting method. The code below will add a new cache item with a sliding expiration of 5 seconds.

object ret;
CacheItemPolicy pol = new CacheItemPolicy();
pol.SlidingExpiration = new TimeSpan(0, 0, 5);
ret = MemoryCache.Default.AddOrGetExisting("Key2", 
                   "Value 2", pol);
if (ret == null) {
MessageBox.Show("Key did NOT exist");
}
else {
MessageBox.Show("The Key did already exist");
}

Set Method

The Set method adds an entry into the cache if the specified key value does not exist. However, if the key value does exist, it will update the value for that key in the cache. I prefer to use this method over the Add or AddOrGetExisting as I typically just want to either add, or update, and not worry about whether I have created the value previously or not. This method does not return any value.

MemoryCache.Default.Set("Key3", "Value 3", 
     DateTimeOffset.Now.AddSeconds(5));

You can use a CacheItemPolicy to set a sliding expiration on the item to cache.

CacheItemPolicy pol = new CacheItemPolicy();
pol.SlidingExpiration = new TimeSpan(0, 0, 5);
MemoryCache.Default.Set("Key3", "Value 3", pol);

Notify Before Removal from Cache

Just before an item is to be removed from the cache because it is expiring, you may create a method to respond to this event. Write the following method to accept a CacheEntryUpdateArguments object. Within this method body you can write whatever code you want. In the sample below I am just writing out the Key and the reason for the removal.

private void UpdateHandler(CacheEntryUpdateArguments e) {
Console.WriteLine(e.Key);
Console.WriteLine(e.RemovedReason.ToString());
}

Once you have this method written, you assign that method to the UpdateCallback property of a CacheItemPolicy object. The code snippet below shows you how you assign this method to the UpdateCallback property.

CacheItemPolicy pol = new CacheItemPolicy();
pol.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(3);
pol.UpdateCallback = UpdateHandler;
MemoryCache.Default.Set(THE_KEY, "Update 3", pol);

If you run the above code and wait a few seconds, you will see a couple of messages printed in the Output window.

Within the UpdateHandler method you also have the option to change the value in the cache and place it back into the cache. You do this by assigning a new CacheItem object with the same key and a value to the e.UpdatedCacheItem property. You must also set the e.UpdatedCacheItemPolicy property to a new CacheItemPolicy object. When this method ends, the item is not removed and is updated within the cache. The code to do this is shown below.

private void UpdateHandler(CacheEntryUpdateArguments e) {
Console.WriteLine(e.Key);
Console.WriteLine(e.RemovedReason.ToString());
e.UpdatedCacheItem = new CacheItem(e.Key, "My New Value");
CacheItemPolicy pol = new CacheItemPolicy();
pol.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(10);
pol.UpdateCallback = UpdateHandler;
e.UpdatedCacheItemPolicy = pol;
}

Notify After Removal from Cache

If you do not care to update an item in the cache, you may just respond to the RemovedCallback event. The design pattern is similar to what you just wrote in the previous example. First create a method that accepts a CacheEntryRemovedArguments object. The only two properties in that object you care about are the e.RemovedReason and the e.CacheItem. The e.CacheItem object contains the item that was just removed from the cache.

private void RemovedHandler(CacheEntryRemovedArguments e) {
  Console.WriteLine(e.RemovedReason.ToString());
  Console.WriteLine("Removed Handler: " + e.CacheItem.Key);
}

With the RemovedHandler method created, you may now set the RemovedCallback property of a CacheItemPolicy object. You then use that CacheItemPolicy object to add a new item into the MemoryCache object.

CacheItemPolicy pol = new CacheItemPolicy();
pol.SlidingExpiration = new TimeSpan(0, 0, 3);
pol.RemovedCallback = RemovedHandler;
MemoryCache.Default.Set("Key3", "Remove 3", pol);

If you run the above code, then either let the value expire, or explicitly remove the item from cache, the RemovedHandler method is called.

Summary

In this blog post you learned to call the AddOrGetExisting method. This method is different from the Add method as it either adds an item to the cache, or retrieves one if they key already exists. You also learned to use the Set method to either add a new item to the cache, or update an item in the cache if it already exists. Providing a couple of callback functions to the CacheItemPolicy lets you respond when an item is about to be deleted from the cache, or after it has already been deleted.

Sample Code

You can download the code for this sample at www.pdsa.com/downloads. Choose the category “PDSA Blogs”, then locate the sample Caching for Non-Web Applications.

Caching for Non-Web Applications – Part 1

A great feature of ASP.NET applications is the Cache class which allows you to store values that are commonly used. Caching data can avoid round-trips to database servers, which can save a lot of time. Until 2010, there was no good way in a Windows Service, Windows Form or WPF application to cache data except by writing your own class. Enter the MemoryCache class, part of the System.Runtime.Caching namespace. This class allows you to add data to a cache and set a time-out so that data can be removed from memory when it is no longer used. This blog post will show you the basics of using this class.

Add Key/Value Pairs

The MemoryCache class has a Default property that refers to a single instance of a MemoryCache. For most applications, you only require one cache object. Of course, you may always create a new instance of a MemoryCache object if you need additional cache objects for your application. In this blog post you are going to just use the default instance.

To add a new value to the cache, you supply three items; a unique key, a value to insert, and how long you want the value to stay in the cache. You are not allowed to insert a null value into the cache, but any other value is allowed. The following code snippet shows the basics of adding a new value to the default MemoryCache instance.

MemoryCache.Default.Add("Key1", "Value 1",
   DateTimeOffset.Now.AddSeconds(5));

The first parameter you pass to the Add method is a unique key value that you use to retrieve the value later. The second parameter is the value to add. In this case, I just added a simple string, however, this can be any data type. The last parameter is a DateTimeOffset type to specify how much time the item should stay in the cache before it is automatically removed.

Check to See if Value was Inserted

Instead of just calling the Add method blindly as I did in the previous code snippet, you should check to see if the value was added. If you attempt to add the same key value to the same cache, the call will fail and the value is not updated. You can check the return value from the Add method to determine if the value was added.

bool ret;
ret = MemoryCache.Default.Add("Key1", "Value 1", 
           DateTimeOffset.Now.AddSeconds(5));
if (ret) {
MessageBox.Show("Key did NOT exist");
}
else {
MessageBox.Show("The Key did already exist");
}

Add Using a Cache Policy

If you wish to set other meta-data information about the item in your cache, create a CacheItemPolicy object and use that to add your item. One of the things you can do with a CacheItemPolicy is set a SlidingExpiration property. The previous code set an absolute time to expire your cache object. The SlidingExpiration property is a TimeSpan to keep the item in your cache, but that time span renews each time the item in the cache is accessed.

bool ret;
CacheItemPolicy pol = new CacheItemPolicy();
pol.SlidingExpiration = new TimeSpan(0, 0, 5);
ret = MemoryCache.Default.Add("Key1", "Value 1", pol);
if (ret) {
MessageBox.Show("Key did NOT exist");
}
else {
MessageBox.Show("The Key did already exist");
}

In the previous code the SlidingExpiration property of a new CacheItemPolicy object is set to 5 seconds. If you access the item in the cache at 4 seconds, then the item will stay in the cache for another 5 seconds. If you access it again after 3 seconds, then another 5 seconds is added on. However, if you do not access the item, then that item is removed from the cache after 5 seconds has elapsed.

Add Using the Default Indexer

If you wish to add an item without setting any expiration time, you can use the default indexer. Pass the key name within square brackets to either add a new, or update an existing key, within the MemoryCache object.

MemoryCache.Default["Key1"] = "Value 1a";

Access the Data in the Cache

After you have entered data in the cache, you need to retrieve it, check to see if it is still in there, count it, etc. The MemoryCache object, of course, supplies you with the appropriate methods to perform these operations. To retrieve a value, use the Get method. You should check to see that the key exists before you retrieve it.

if (MemoryCache.Default.Get("Key1") != null) {
MessageBox.Show(
    MemoryCache.Default.Get("Key1").ToString());
}
else {
MessageBox.Show("Cache Item Does Not Exist");
}

If you attempt to Get a key that does not exist within the cache a null value is returned. If it does exist, the Get method returns an object type to you. You will need to cast the data to the appropriate data type prior to using it.

Use the Default Indexer

Instead of using the Get method you may also use the indexer property to retrieve a value from the cache. The indexer to the MemoryCache object is just like any other .NET indexer. You pass the key name within square brackets to the MemoryCache object and it will return the value if one exists. The code below provides the exact same functionality as the previous sample.

if (MemoryCache.Default[THE_KEY] != null) {
MessageBox.Show(MemoryCache.Default[THE_KEY].ToString());
}
else {
MessageBox.Show("Cache Item Does Not Exist");
}

Using the Contains Method

Instead of using the Get method and having it return a null if the key does not exist, use the Contains method to just check to see if a key exists in the cache. The code below shows an example of using the Contains method.

if (MemoryCache.Default.Contains("Key1")) {
MessageBox.Show("Cache Item Exists");
}
else {
MessageBox.Show("Cache Item Does NOT Exist");
}

Count the Items in the Cache

Call the GetCount method to determine how many items are currently cached in the MemoryCache object. This method returns an integer value.

MessageBox.Show(MemoryCache.Default.GetCount().ToString());

Remove an Item from the Cache

At some point, you might with to manually remove an item from the cache, instead of just letting the item expire. To accomplish this, call the Remove method passing in the key value.

MemoryCache.Default.Remove("Key1");

Summary

In this blog post you were introduced to the MemoryCache object. This object allows you to cache data in any type of application, even a non-web application. This class is like the ASP.NET Cache object in that it allows you to time-out values you put into the cache. You can add values to the cache using the Add or default indexer. Retrieve values from the cache using the Get method or the default indexer. You may also count, check for key existence, and remove items from the cache. In the next blog post, you will learn to use the AddOrGetExisting and Set methods. In addition you will learn how to be notified when an item is removed from the cache.

Sample Code

You can download the code for this sample at www.pdsa.com/downloads. Choose the category “PDSA Blogs”, then locate the sample Caching for Non-Web Applications.

Unit Testing Using the Command Line

This is another in my series of blog posts on unit testing. If you are not familiar with unit testing, go back and read these posts.

In this post, you are going to learn to run unit tests from the command line. This allows you to schedule tests using task manager or any other automated scheduling tool. The VSTest.Console.exe is the tool you use as a .NET developer to run your unit tests in your .NET test dll.

Simple VSTest.Console Run

The VSTest.Console.exe is typically installed into the following path: C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow. When you run this tool, you need to prefix this path to the .exe, or add this path to the PATH environment variable. If you open a Developer Command Prompt for VS2015 (Figure 1) this path will already be included.


Figure 1: Use the Developer Command Prompt

If you have been creating the project as you have been following along with this series of blog posts, you have a DLL named MyClassesTest.dll located in the \bin\Debug folder of where your project is located on your disk. Open a Developer Command Prompt and navigate to that folder. Type in the following in your command window.

VSTest.Console.exe MyClassesTest.dll

Press the Enter key and you should see something that looks like Figure 2. You may or may not have the warnings depending on if you added the DeploymentItem attributes.


Figure 2: A simple run of the VSTest.Console

View Installed Loggers

Now that you know how to run your unit tests from the command line, you now need to learn to log the results to a file that you can look at later. If you are going to be running your unit tests overnight, you want to come back in the morning to see the results. If they are just sitting in a command window, you could accidentally close that window and you would lose the results. Instead, the VSTest.Console utility has a set of loggers that you can use. Type in the following in the command window.

VSTest.Console.exe /ListLoggers

Press the Enter key to see a screen that looks like Figure 3.


Figure 3: View the log options you can use with VSTest.Console

The ConsoleLogger is the one you are currently looking at in your command window. The TfsLogger is useful if you are using Team Foundation Server as it allows you to send the results to TFS so you can assign work items based on any failed unit tests. The last one is the one that will be useful if you do not have TFS. The TrxLogger creates a .trx file which you can load into Visual Studio and see a list of all of your unit tests. You can then click on each test and see the results, and the outputs for that test.

Using Logger

Let's take a look at using the TrxLogger option when using the VSTestConsole.exe utility. Type in the following into the command window.

VSTest.Console.exe MyClassesTest.dll /Logger:trx

Press the Enter key and the unit testing will run. The results are now stored in a .trx file located in the TestResults folder under your \bin\Debug folder. Each time you run a new .trx file is added with a later date and time add to the file name.

Double click on any of the *.trx files and it will load the results into a Test Results window in Visual Studio as shown in Figure 4. You can double-click on any of the tests to see the output from that test. 


Figure 4: Visual Studio can display all results from a .trx file

Run Specific Test(s)

The VSTest.Console utility allows you to specify single or multiple test method names to run. If you are just testing one or two items, there is no reason to run all the tests in your DLL. Add the /Tests parameter on the command line followed by a comma-delimited list of method names you wish to execute. Type the following into your command window.

VSTest.Console.exe MyClassesTest.dll /Tests:FileNameDoesExist

Press the Enter key and you should see a result that looks like Figure 5.


Figure 5: The /Tests parameter does pattern matching on your method names

Notice that multiple tests where run even though you only specified a single name. This is because the /Tests parameter uses pattern matching on your method names. It will find any method that starts with the name you pass in and run those methods.

You can use a comma-delimited list to specify different sets of methods to run. Type the following into your command window.

VSTest.Console.exe MyClassesTest.dll 
   /Tests:FileNameDoesExist,
    FileNameNullOrEmpty_ThrowsArgumentNullException

Press the Enter key and you should see results that look similar to Figure 6.


Figure 6: You may use a comma-delimited list after the /Tests parameter

Filter Tests to Run based on Attributes

As mentioned in the blog post on attributes, the Priority attribute is not used by the unit test framework. However, when you use the VSTest.Console utility, you are allowed to filter based on the Priority attribute. Type in the following to the command window and you can run just those methods that have the Priority(1) attribute.

VSTest.Console.exe MyClassesTest.dll 
   /TestCaseFilter:"Priority=1" 

The /TestCaseFilter lets you specify attributes and specific names of methods to run. For example, if you want to just run one test with the name of FileNameDoesExist, you type in the following into the command window to run that one test.

VSTest.Console.exe MyClassesTest.dll 
   /Name:"FileNameDoesExist" 

Another attribute you can specify to run is TestCategory. Run the following in the command window to just run those tests marked with [TestCategory(“NoException”)].

VSTest.Console.exe MyClassesTest.dll
   /TestCaseFilter:"TestCategory=NoException"

You are not allowed to use both the /TestCaseFilter parameter and the /Tests parameter together. You must just run one or the other.

Summary

Running unit tests in a batch is made easy with the VSTest.Console.exe utility. This utility allows you to log the output to a file for later review. You can also log to TFS to help you assign work items to unit tests that fail. The VSTest.Console utility also lets you filter the tests to run using either a /Tests parameter, or a /TestCaseFilter parameter.

Sample Code

You can download the code for this sample at www.pdsa.com/downloads. Choose the category “PDSA Blogs”, then locate the sample Unit Testing Using the Command Line.

Using Assert Classes and Methods in Unit Tests

If you have been following my blog posts on unit testing, you have used the Assert class to signify if a unit test is successful or not. The following are my previous posts on unit testing. If you are not familiar with unit testing, go back and read these posts.

You have used the Inconclusive, IsTrue, IsFalse and Fail methods. In this blog post you will learn about some of the other methods you can utilize in the Assert class. In addition you will learn about two additional assert classes you may take advantage of when writing unit tests.

Assert Class

There are many methods in the Assert class. I won’t explain each one, but I will expose you to some so you can get an idea of what is available to use. You should search the MSDN documentation to see the complete list of properties and methods available to you in the Assert class.

Common Parameters to Assert Methods

Most of the methods you may invoke on the Assert class include an overload that allows you to specify a message to display in the test results. An additional overload lets you specify the message using the standard string.Format() tokens and a parameter array of the values to use to replace into the message.

[TestMethod]
public void FileNameDoesExistSimpleMessage() {
FileProcess fp = new FileProcess();
bool fromCall;
fromCall = fp.FileExists(_GoodFileName);
Assert.IsTrue(fromCall, "File Does Not Exist.");
}

When you run the above test, your Test Explorer window will show the hard-coded message after you click on the failed test (Figure 1).


Figure 1: Display hard-coded messages into the results window.

To include some of the data you gathered during the test, use the format items just as you use in the string.Format() method.

[TestMethod]
public void FileNameDoesExistSimpleMessageWithParams() {
FileProcess fp = new FileProcess();
bool fromCall;
fromCall = fp.FileExists(_GoodFileName);
Assert.IsTrue(fromCall, 
"File {0} Does Not Exist.", 
_GoodFileName);
}

When you run this test, you get the message shown in Figure 2.


Figure 2: Display messages with data from the unit test itself.

AreEqual Method

The AreEqual method compares two variables of the same data type to determine if they are equivalent. There are overloads for each of the different data types such as double, single, int, etc. You may add your own custom message, and specify format items as explained earlier. Below are just a few of the data types you can compare.

Assert.AreEqual(int, int);
Assert.AreEqual(bool, bool);
Assert.AreEqual(double, double);

Here is an example using integer data types.

[TestMethod]
public void AreEqualTest() {
int x = 1;
int y = 1;
Assert.AreEqual(x, y);
}

When the two variables you wish to compare are of a string data type, you may also specify a CultureInfo object to handle string comparisons based on the language of the user. You may also specify a boolean value to perform a case-sensitive or case-insensitive comparison of the strings.

AreEqual(string, string)               // case-insensitive
AreEqual(string, string, true)         // case-sensitive
AreEqual(string, string, CultureInfo)  // Use a culture

AreNotEqual Method

To compare two values to see if they are not equal you use the AreNotEqual method. This method, like the AreEqual method, has several overloads you can use based on the different data types. Below is a sample of using the AreNotEqual method.

[TestMethod]
public void AreNotEqualTest() {
int x = 1;
int y = 2;
Assert.AreNotEqual(x, y);
}

AreSame Method

To compare two objects to see if they are the same object. For example, if you write the following test:

[TestMethod]
public void AreSameTest() {
FileProcess x = new FileProcess();
FileProcess y = new FileProcess();
Assert.AreSame(x, y);
}

This test will fail, because the two objects point to two different objects. If you change this test to look like the following, where you assign the variable x to the variable y, then this test will succeed.

[TestMethod]
public void AreSameTest() {
FileProcess x = new FileProcess();
FileProcess y = x;
Assert.AreSame(x, y);
}

AreNotSame Method

To compare two objects to see if they are NOT the same object. In this case, the following test would succeed.

[TestMethod]
public void AreNotSameTest() {
FileProcess x = new FileProcess();
FileProcess y = new FileProcess();
Assert.AreNotSame(x, y);
}

IsInstanceOfType Method

You can use this method to determine if an object returned from a method is of a certain type. For example, you may have a method that returns an interface or a base class. When you call this method from your unit test, you might wish to compare the type of instance that is returned against the type you are expecting.

Look at the class diagram in Figure 3 in which you have a Person class with two properties. Both the Employee and the Supervisor classes inherit from the Person class. The PersonManager class has a method named CreatePerson that returns a Person object. Depending on the parameters you pass to the CreatePerson method, determines the type of object passed back. Either an Employee or a Supervisor object is returned.


Figure 3: A class diagram for our example

You can write a unit test to determine what the type is. In the unit test below, you pass a true value to the CreatePerson method. This value tells CreatePerson to return a Supervisor object. You use the IsInstanceOfType method to compare the variable per against the typeof(Supervisor).

[TestMethod]
public void IsInstanceOfTypeTest() {
PersonManager mgr = new PersonManager();
Person per;
per = mgr.CreatePerson("Paul", "Sheriff", true);
Assert.IsInstanceOfType(per, typeof(Supervisor));
}

IsNotInstanceOfType Method

This method is the same as the IsInstanceOfType, but checks to see if the instance returned is not of a specific type.

IsNull Method

Call this method to compare the return result from a method against null. If the return result is a null, then the test succeeds. In the unit test below, if you pass an empty string as the first name to the CreatePerson method, that method returns a null object.

[TestMethod]
public void IsNullTest() {
PersonManager mgr = new PersonManager();
Person per;
per = mgr.CreatePerson("", "Sheriff", true);
Assert.IsNull(per);
}

IsNotNull Method

This method is the same as the IsNull method, but checks to see if the value returned is not null.

StringAssert

When working with strings, you commonly need to check to see if one string is contained within another, or if one string matches a regular expression, or a string starts or ends with a specific character or other string value. To test these in a unit test, use the StringAssert class with any of the following methods.

  • Contains
  • DoesNotContain
  • Matches
  • DoesNotMatch
  • StartsWith
  • EndsWith

CollectionAssert

Many methods you write in your applications deal with collections of data. This data could be retrieved from a database, an XML file, or simply arrays of objects you create in your code. The CollectAssert class allows you to test a known set of data in a collection against the collection returned from the method you are testing. You do not need to do any looping through the collections, the CollectionAssert class will do all of that for you. Below is a list of the various methods you can use.

  • AllItemsAreInstancesOfType
  • AllItemsAreNotNull
  • AllItemsAreUnique
  • AreEqual
  • AreNotEqual
  • AreEquivalent
  • AreNotEquivalent
  • Contains
  • DoesNotContain
  • IsSubsetOf
  • IsNotSubsetOf

Summary

In this post, you learned more about the different methods in the Assert class. You also learned about two additional classes to help you test strings and collections. All methods in the various Assert classes contain overloads to allow you to add your own custom message to display in the test results. With this many methods available to you, writing your unit tests should go quickly.

Sample Code

You can download the code for this sample at www.pdsa.com/downloads. Choose the category “PDSA Blogs”, then locate the sample Using Assert Classes and Methods in Unit Tests.

Add Attributes to Unit Tests

In my previous blog posts, I introduced you to creating unit tests with Visual Studio. The following is the list of blog posts published thus far.

You have seen a few different attributes such as [TestClass], [TestMethod], and [TestInitialize] used to decorate classes and methods. There are several more attributes that you should be aware of. You may or may not use all the attributes presented in this blog post, but you may have a need for them at some time or another.

DataSource Attribute

The unit test framework in Visual Studio can data-drive your unit tests. This means you can read data from a data store and execute a single test repeatedly using the data read in. A later blog post will discuss how to use data-driven tests, so this attribute is not covered here.

Description Attribute

Add a Description attribute to any unit test method to describe why you wrote a particular unit test. It is recommended that you use good, long, description name for the unit test method name as well as the Description attribute. This attribute is not used by the unit test framework, nor does it show up anywhere within the Test Explorer window.

[Description("Check to see if a file exists.")]
public void FileNameDoesExist() {
}
[Description("Check to see if file does not exist.")]
public void FileNameDoesNotExist() {
}
[Description("Check for a thrown ArgumentNullException.")]
public void 
  FileNameNullOrEmpty_ThrowsArgumentNullException () {
}
[Description("Check for a thrown ArgumentNullException
              using ExpectedException.")]
public void FileNameNullOrEmpty_
   ThrowsArgumentNullException_UsingAttribute () {
}

DeploymentItem Attribute

You may add as many DeploymentItem attributes as you need to specify files and folders to copy to the directory where the unit test runs. The DeploymentItem attribute accepts one or two parameters. The first parameter is a folder or a file name. The path is always relative the build output folder. The second parameter, if passed, is to a new path to copy the data in the first parameter. This second path can be relative to the output folder, or can be an absolute path. It is highly recommended you use a relative folder to allow tests to run seamlessly on different machines.

For our simple example, you do not need to use any DeploymentItem attributes, but below is a sample that would copy two files named DeploymentFile1.txt and DeploymentFile2.txt to the build output folder. It is assumed these two files already exist. If the folder or file does not exist, no error is thrown when running in Visual Studio, the test simply continues. However, if you use the command line utility, a warning is generated.

[DeploymentItem("DeploymentFile1.txt")]
[DeploymentItem("DeploymentFile2.txt")]
public void FileNameDoesExist() {
}

Ignore Attribute

The Ignore attribute is intended to be a temporary attribute you add to skip one or more unit test methods.

[Ignore]
public void FileNameDoesExist() {
}

Owner Attribute

The Owner attribute allows you to specify the name of the developer responsible for the unit test. This helps with the assignment of work items to the developer of a unit test that breaks.

[Owner("PaulS")]	
public void FileNameDoesExist() {
}
[Owner("PaulS")]
public void FileNameDoesNotExist() {
}
[Owner("JohnK")]
public void 
  FileNameNullOrEmpty_ThrowsArgumentNullException () {
}
[Owner("JohnK")]
public void FileNameNullOrEmpty_
   ThrowsArgumentNullException_UsingAttribute () {
}

After the test runs, right mouse click on the test results in the Text Explorer window and select the Group By menu (Figure 1).


Figure 1: Right mouse click to group by traits 

Next select the Traits menu to sort by any attributes you have added (Figure 2).


Figure 2: The Test Explorer window can group results by different attributes you add.

Priority Attribute

The Priority attribute, like the Owner attribute, is considered a “Trait” by the Test Explorer window. It is not used by the unit test framework itself, but can be grouped in the Test Explorer window (Figure 3). When using the VSTest.Console.exe command-line utility, you may filter the tests to run by the Priority attribute.

[Priority(0)]	
public void FileNameDoesExist() {
}
[Priority(1)]
public void FileNameDoesNotExist() {
}
[Priority(1)]
public void 
  FileNameNullOrEmpty_ThrowsArgumentNullException () {
}
[Priority(0)]
public void FileNameNullOrEmpty_
   ThrowsArgumentNullException_UsingAttribute () {
}


Figure 3: Tests can display under multiple traits.

TestCategory Attribute

The TestCategory attribute, like Owner and Priority, is a “Trait” you may group upon in the Test Explorer window (Figure 4). You define any category name you wish and assign that name to one or many tests. After all tests have run, you may filter and sort within the Test Explorer window on the category names.

[TestCategory("NoException")]
public void FileNameDoesExist() {
}
[TestCategory("NoException")]
public void FileNameDoesNotExist() {
}
[TestCategory("Exception")]
public void 
  FileNameNullOrEmpty_ThrowsArgumentNullException () {
}
[TestCategory("Exception")]
public void FileNameNullOrEmpty_
   ThrowsArgumentNullException_UsingAttribute () {
}



Figure 4: Categories are common traits to use besides Owner.

Timeout Attribute

Use the Timeout attribute to specify how long a specific method is allowed to run before the unit test framework kills the test and marks it as a failure. The value you specify is expressed in milliseconds. In the following example, the unit test framework will allow the method to execute for only 5 seconds before it will stop the execution and throw an AssertFailedException.

[Timout(5000)]
public void FileNameNullOrEmpty_
   ThrowsArgumentNullException_UsingAttribute () {
}

Summary

In this blog post you learned about many of the attributes you may apply to unit test classes and methods. The most common attributes you should add are Description, Owner and TestCategory. Description is optional, and should be used in combination with a descriptive unit test method name. The Owner, Priority and TestCategory attributes may be grouped within the Test Explorer window.

Sample Code

You can download the code for this sample at www.pdsa.com/downloads. Choose the category “PDSA Blogs”, then locate the sample Add Attributes to Unit Tests.

String Interpolation in C# 6.0

I just found this handy shorthand for string.Format() which is available in C# 6.0. I am sure you have all used string.Format() before. Let's say you want to do a little formatting with some data in some variables like the following:

string first = "Paul";
string last = "Sheriff";
Console.WriteLine(string.Format("{0} {1}", first, last));

In C# 6.0 you may now use the string interpolation character, the dollar sign, instead of the string.Format().

string first = "Paul";
string last = "Sheriff";
Console.WriteLine($"{first} {last}");

Both of the above pieces of code will place the string "Paul Sheriff" into your output window.

I really like this new format. It is much easier to read and understand where exactly your variables are going without having to count the number of parameters and figure out which ones go where in your string.

You may also combine the $ with the @ sign if you are going to have a backslash in your string. You must specify them in the order $@ for the interpolation to work correctly. Here is an example of using these two together.

string dir = "Windows";
Console.WriteLine($@"C:\{dir}");

The above code will display the string "C:\Windows" in your output window.

Have fun with this new feature of C# 6.0.

Unit Test Initialization and Cleanup

This blog post continues our look at unit testing techniques. See my previous two blog posts for the sample used for testing.

In this blog post you learn about initialization and cleanup of the test environment. There are different methods of initialization and cleanup available to developers in Visual Studio. This blog post will introduce you to each and describe how to use each one.

Overview

There are six attributes you can use to perform initialization and cleanup. Which ones you use, depends on when you need to initialize something and/or clean something up. You can initialize/cleanup once for all classes within a unit test assembly. You can initialize/cleanup once for all test methods within a test class. You can initialize/cleanup before and after each test method runs within a class.

  • AssemblyInitialize
  • AssemblyCleanup
  • ClassInitialize
  • ClassCleanup
  • TestInitialize
  • TestCleanup

Add one or more of these attributes to a single method within your classes. You can see an example of how these attributes might be applied to a set of classes in your assembly displayed in Figure 1. The order in which these methods run is as follows.

  1. AssemblyInitialize
  2. ClassInitialize
  3. TestInitialize
  4. TestMethod, TestMethod, TestMethod, etc.
  5. TestCleanup
  6. ClassCleanup
  7. AssemblyCleanup


Figure 1: Overview of how test initialization and cleanup methods execute

Assembly Initialization and Clean Up

If you have several classes within a specific assembly and you need to create a database with some test records in some tables prior to running all, or the majority, of tests within these classes, create that database within a method decorated with the [AssemblyInitialize] attribute.

I think it is a good idea to create a separate class that is only used for assembly initialization and cleanup. Create a new class with the name of MyClassesTestInitialization within your test project. Add the following method to this class.

[AssemblyInitialize()]
public static void AssemblyInitialize(TestContext tc) {
  // TODO: Initialize for all tests within an assembly
  tc.WriteLine(“In AssemblyInitialize”);
}

Only one method within your entire assembly may be decorated with the [AssemblyInitialize] attribute. This method must be static and the test framework will pass in an instance of the TestContext object.

If you wish to delete any files or a database after all methods have run within an assembly, place the code to perform these operations within a method decorated with the [AssemblyCleanup] attribute. Only one method within your entire assembly may be decorated with the [AssemblyCleanup] attribute. This method must be declared as static.

[AssemblyCleanup()]
public static void AssemblyCleanup() {
  // TODO: Clean up after all tests in an assembly
}

Class Initialization and Clean Up

Just as you create classes in your application to encapsulate a specific set of functionality, organize your unit test classes the same way. In the test program for this series of blog posts, I have a FileProcess class. There is currently only one method in that class, but in a real application, there would probably be many methods all dealing with file IO.

In the FileProcessTest class you only have unit test methods that perform testing on methods within the FileProcess class. Within the unit test class, you may need to create some files (or a database, or other data) that is needed when running all or the majority of the test methods. If that is the case, create a method within that class that is decorated with the [ClassInitialize] attribute. Only one method within your test class may be decorated with the [ClassInitialize] attribute.

[ClassInitialize()]
public static void ClassInitialize(TestContext tc) {
  // TODO: Initialize for all tests within a class
  tc.WriteLine(“In ClassInitialize”);
}

If you create a file (or a database, or other data), you might want to delete that file, or other data after all of the tests have run in that class. Add a method to perform this cleanup within a method decorated with the [ClassCleanup] attribute. Only one method within your class may be decorated with the [ClassCleanup] attribute.

[ClassCleanup()]
public static void ClassCleanup() {
  // TODO: Clean up after all tests within this class
}

Test Initialization and Clean Up

The method decorated with the [ClassInitialize] attribute only runs once the first time a class is created. A method decorated with the [TestInitialize] attribute will run before each test method within that class. If you have four methods in a test class, the TestInitialize method will run four times. As an example, if you need a specific file name to exist before all, or the majority, of tests within a class are run, create a method like the one shown below.

[TestInitialize()]
public void TestInitialize() {
  // Create the Test.txt file.
  File.AppendAllText("Test.txt", "Some Text");
}

The above code will run before each test method is executed. If you did not clean up after each test, then you would have four lines of text within the Test.txt file. To clean up after each method, write a method that has the [TestCleanup] attribute attached to it.

[TestCleanup()]
public void TestCleanup() {
  // Delete Text.txt file
  if (File.Exists("Test.txt")) {
    File.Delete("Test.txt");
  }
}

Since this method runs after each unit test method, each new test method that runs will have a file available to it that only has a single line of text within it.

Check for Test Name

Within the TestInitialize method you can check the TestName property of the TestContext object to see if a specific test is being run. If it is, you could do a specific initialization just for that test. In the following sample, you check to see if the current test being run is “FileNameDoesExist” and if it does, you create the file contained within the _GoodFileName property. Of course, you are already doing this in the FileNameDoesExist method already, so you do not need to do it in the TestInitialize method, but it does show an example of what you could do.

[TestInitialize]
public void TestInitialize() {
TestContext.WriteLine("In TestInitialize");
if (TestContext.TestName == "FileNameDoesExist") {
if (!string.IsNullOrEmpty(_GoodFileName)) {
TestContext.WriteLine("Creating file: " + _GoodFileName);
// Create the 'Good' file.
File.AppendAllText(_GoodFileName, "Some Text");
}
}
}

Summary

In this blog post you learned about initialization and clean up for unit tests. You have three ways to perform initialization and clean up in the unit test framework. You just need to decide where in the process you need to perform the initialization. Then decide how much clean up you need, and write the appropriate methods, and decorate with the appropriate attributes.

Sample Code

You can download the code for this sample at www.pdsa.com/downloads. Choose the category “PDSA Blogs”, then locate the sample Unit Test Initialization and Cleanup.


Avoid Hard-Coding in Unit Tests

In my previous blog post entitled Introduction to Unit Testing with Visual Studio, I introduced you to creating unit tests with Visual Studio. A method named FileExists was created to which you pass a file name to see if it exists. In the tests you created, you use hard-coded file names to test. Just as you wouldn’t hard-code values in a normal application, you should not do this with unit tests either. In this blog post you will learn to use constants, a configuration file, and how to create and delete test files.

Please go read the previous blog post and create the project, or download the project at http://www.pdsa.com/downloads and select “Introduction to Unit Testing” from the list.

Use a Constant

Constants are a great way to centralize hard-coded data that would otherwise be repeated throughout an application. In this case, you are going to replace the hard-coded file name used in the FileNameDoesNotExist method with a constant. At the top of the FileProcessTest class, add the following constant.

private const string BAD_FILE_NAME = @"C:\NotExists.bad";

Modify the FileNameDoesNotExist to use this new constant as shown in the code snippet below.

public void FileNameDoesNotExist() {
  FileProcess fp = new FileProcess();
  bool fromCall;
  fromCall = fp.FileExists(BAD_FILE_NAME);
  Assert.IsFalse(fromCall);
}

Use a Configuration File

A constant is a good option for the “bad” file name. For the “good” file name you wish to test to see exists, let’s add that to a configuration file so it can be modified easily. In fact, let’s add a replaceable token called [AppPath] that will figure out the appropriate path to use based on the machine the test is running upon.

Right mouse click on the FileProcessTest project and select Add | New Item… from the menu. From the template dialog select General | Application Configuration File. The name should already be set to App.config, so click on the Add button.

Within the <configuration> element add an <appSettings> section. Within the <appSettings> section add a key called GoodFileName with a value of [AppPath]\TestFile.text as shown below.

<appSettings>
  <add key="GoodFileName" value="[AppPath]\TestFile.txt"/>
</appSettings>

In order to retrieve this value from the configuration file, you need to use the ConfigurationManager class from the System.Configuration namespace. By default, the System.Configuration DLL is not added to a test project. Right mouse click on References folder in your FileProcessTest project and select Add Reference from the menu. From the dialog select Assemblies | Framework. Locate the System.Configuration dll and select the check box. Click the OK button to add this DLL to your test project.

At the top of the FileProcessTest class, add a using statement for the System.Configuration namespace.

using System.Configuration;

Add private field to FileProcessTest class to hold the value you are going to retrieve from the configuration file. Set the name of this field to _GoodFileName as shown below.

private string _GoodFileName;

Add a constructor to the FileProcessTest class in which you will read the GoodFileName value from the configuration file. Within this constructor you will replace the token [AppPath] with the value from the Environment.SpecialFolder.ApplicationData. This enumeration, supplied by .NET, when passed to the GetFolderPath, returns the pre-defined path for any data you need to store for this application. The location may vary from OS to OS, but on Windows 10 it is C:\\Users\\YOUR_USERNAME\\AppData\\Roaming. Write the constructor as shown below.

public FileProcessTest() {
  _GoodFileName =
     ConfigurationManager.AppSettings["GoodFileName"];
  if (_GoodFileName.Contains("[AppPath]")) {
     _GoodFileName = _GoodFileName.Replace("[AppPath]", 
        Environment.GetFolderPath(
          Environment.SpecialFolder.ApplicationData));
  }
}

Locate and modify the FileNameDoesExist method to use this new property name.

[TestMethod]
public void FileNameDoesExist() {
  FileProcess fp = new FileProcess();
  bool fromCall;
  fromCall = fp.FileExists(_GoodFileName);
  Assert.AreEqual(true, fromCall);
}

Create / Delete File

Instead of you having to create the file name in the location specified, prior to running the FileNameDoesExist test, you should create the file name within the method itself. You should delete the file after you have performed the FileExists call so you don’t keep files around you don’t need. Modify the FileNameDoesExist method to look like the following.

[TestMethod]
public void FileNameDoesExist() {
  FileProcess fp = new FileProcess();
  bool fromCall;
  if (!string.IsNullOrEmpty(_GoodFileName)) {
    // Create the 'Good' file.
    File.AppendAllText(_GoodFileName, "Some Text");
  }

  fromCall = fp.FileExists(_GoodFileName);
  // Delete file
  if (File.Exists(_GoodFileName)) {
    File.Delete(_GoodFileName);
  }

  Assert.IsTrue(fromCall);
}

TestContext

When the unit test framework creates an instance of a test class (a class marked with the [TestClass] attribute), the test framework creates a TestContext object. This object contains properties and methods related to testing. To access this TestContext object, you must create a public property named TestContext in each of your test classes. The test framework checks for this property and inserts the instance of this TestContext into your property.

private TestContext _TestInstance;  
public TestContext TestContext  
{  
    get { return _TestInstance; }  
    set { _TestInstance = value; }  
}

One of the things you can do with this TestContext is to use the WriteLine method to add some output into the test results. Add the lines shown in bold below to write some messages about what file you are creating into the output area of the test results.

[TestMethod]
public void FileNameDoesExist() {
  FileProcess fp = new FileProcess();
  bool fromCall;
  if (!string.IsNullOrEmpty(_GoodFileName)) {
    TestContext.WriteLine("Creating file: " + _GoodFileName);
    // Create the 'Good' file.
    File.AppendAllText(_GoodFileName, "Some Text");
  }
  TestContext.WriteLine("Checking file: " + _GoodFileName);
  fromCall = fp.FileExists(_GoodFileName);
  // Delete file
  if (File.Exists(_GoodFileName)) {
    TestContext.WriteLine("Deleting file: " + _GoodFileName);
    File.Delete(_GoodFileName);
  }
  Assert.IsTrue(fromCall);
}

Run this test, once it is complete, click on the FileNameDoesExist test in the Test Explorer window, locate the Output link at the bottom of the window and click on it. You should then see your messages appear in an output window as shown in Figure 1.


Figure 1: Write output messages using the TestContext property

Summary

In this blog post a constant was used in place of a hard-coded file name. You placed another hard-coded file name into the App.config file in the test project. Within a test method you created a file, tested that file’s existence, then deleted the file. This helps keep that method self-contained and avoids manual setup of files prior to running these tests. Finally, you added a TestContext property to access the WriteLine method of the TestContext property. This allows you to add additional messages into the output of the test results.

Sample Code

You can download the code for this sample at www.pdsa.com/downloads. Choose the category “PDSA Blogs”, then locate the sample Avoid Hard-Coding in Unit Tests.

Introduction to Unit Testing with Visual Studio

Every developer needs to test their code, or have it tested by someone. Many developers are not great at testing their own code. The main reason is we tend to test only the “happy path” through the functionality that we wrote. We often avoid testing the boundaries of our code such as invalid inputs, exceptions that might occur, etc. One way to become a better tester is to start writing unit tests. While it takes more time up-front to write unit tests, it saves a ton of time when you must regression test changes to existing features.

Starting with Visual Studio 2008, Microsoft added a unit testing framework right into Visual Studio. There are also several third-part testing frameworks you may use. In this blog post, you are going to learn the basics of using the unit test framework in Visual Studio.

Our Method to Test

For this blog post, you are going to build a method that checks to see if a file exists. You are then going to build unit tests to check each type of input you can pass to this method.

To start, create a new Class Library project in Visual Studio using C#. Set the name of this class library project to MyClasses. Rename the Class1.cs file created by Visual Studio to FileProcess. Add a method in this class called FileExists as shown in the following code snippet.

public bool FileExists(string fileName) {
  if (string.IsNullOrEmpty(fileName)) {
    throw new ArgumentNullException("fileName");
  }
  return File.Exists(fileName);
}

This is a very simple method, yet it requires at least three unit test methods to ensure this method works with all possible inputs. The three possible values you can pass to the fileName parameter are:

  • A file name that exists
  • A file name that does not exist
  • A null or empty string

Create a Test Project

Right mouse click on your MyClasses solution and choose Add | New Project. From the list of templates, click on the Visual C# | Test | Unit Test Project. Set the Name to MyClassesTest. Click the OK button. Rename the UnitTest1.cs file to FileProcessTest.cs. You are going to test the method in your MyClasses class library, so you need to add a reference to that project. Right mouse click on the References folder in the MyClassesTest project and select MyClasses. Add a using statement at the top of the FileProcessTest.cs file.

using MyClasses;

Create Stubs for all Tests

As you have identified three different tests, it is a good idea to go ahead and write all three methods right away so you don’t forget what you want to test. The code shown below shows how you structure your test class.

[TestClass]
public class FileProcessTest
{
  [TestMethod]
  public void FileNameDoesExist() {
    Assert.Inconclusive();
  }
  [TestMethod]
  public void FileNameDoesNotExist() {
    Assert.Inconclusive();
  }
  [TestMethod]
  public void
     FileNameNullOrEmpty_ThrowsArgumentNullException() {
    Assert.Inconclusive();
  }
}

The first thing you notice about this class is the presence of the [TestClass] attribute before the class definition. This attribute informs the unit test framework that this class is one that can be included in the testing process. Next, you notice that each method is prefixed with a [TestMethod] attribute. Again, this is to inform the unit test framework that this is a test method that needs to run. Within each method, call the Assert.Inconclusive() method. This informs the testing framework that you have not written any code for this test method. This is not a success, or a failure, of the test. This shows up as a skipped test in the Test Explorer window. The advantage of using this method is this gives you a checklist of the tests that you still need to write.

After adding this code, right mouse click in your code window and choose Run Tests from the context-sensitive menu that appears. After the code runs, a Test Explorer window appears with the results of the test(s) as shown in Figure 1.


Figure 1: Skipped tests are the result of the Inconclusive method call

Write the Tests

It is now time to start writing the code in the unit tests to create each of the three possible inputs identified for this method. The first one is to test that a file exists. Modify the FileNameDoesExist method shown below. Feel free to change the drive letter, path and file name to a file that exists on your computer.

[TestMethod]
public void FileNameDoesExist() {
  FileProcess fp = new FileProcess();
  bool fromCall;
  fromCall = fp.FileExists(@"C:\Windows\Regedit.exe");
  Assert.IsTrue(fromCall);
}

After adding this code, right mouse click in your code window and choose Run Tests from the context-sensitive menu that appears. After the code runs, a Test Explorer window appears with the results of the test. If the file exists, the window should display something that looks like Figure 2.


Figure 2: Test results appear in the Test Explorer window

The next method to write is to test for a file that does not exist. Modify the FileNameDoesNotExist method in your FileProcessTest class to test this condition. Write the code shown in the following code snippet.

[TestMethod]
public void FileNameDoesNotExist() {
  FileProcess fp = new FileProcess();
  bool fromCall;
  fromCall = fp.FileExists(@"C:\NotExists.bad");
  Assert.IsFalse(fromCall);
}

Once again, run these tests and you should now see two passed tests in your Test Explorer window.

Handling Exceptions

You should always test for any exceptions being thrown from your methods. There are two ways to handle a thrown exception; add a catch block in your test method or add an [ExpectedException] attribute. In the FileExists method an ArgumentNullException is thrown if a null or blank value is passed to the method. Let’s take a look at the two ways to handle this thrown exception.

Add a test to the FileProcessTest class named FileNameNullOrEmpty_ThrowArgumentNullException_UsingAttribute. Add an [ExpectedException] attribute after the [TestMethod] attribute on this method as shown in the following code snippet.

[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void FileNameNullOrEmpty_
             ThrowArgumentNullException_UsingAttribute () {
  FileProcess fp = new FileProcess();
  fp.FileExists("");
}

Run this test and you should see that this test passes.

The second way to handle this thrown exception is to wrap up the call to the FileExists method within a try…catch block in your test method. The catch block should check to see if the exception is a ArgumentNullException. If it is, then the test received the correct return value. If no exception was thrown, or any other kind of exception is returned from FileExists, call the Assert.Fail() method to let the unit test framework that this test failed. Modify the FileNameNullOrEmpty_ThrowsArgumentNullException method as shown in the following code snippet.

[TestMethod]
public void FileNameNullOrEmpty_ThrowsArgumentNullException()
{
  FileProcess fp = new FileProcess();
  try {
    fp.FileExists("");
  }
  catch (ArgumentNullException) {
    // Test was a success
    return;
  }
  // Fail the test
  Assert.Fail("Call to FileExists() did NOT throw 
               an ArgumentNullException.");
}

Run the unit tests one more time, and you should now see four passed tests in the Test Explorer window.

Summary

Visual Studio makes it easy to get started creating unit tests. Take advantage of the unit test framework built-in to Visual Studio. It is important to think of as many ways as possible to break your code. Then, write all the unit tests to test that your code does not break. Use the ExpectedException attribute to help you with exceptions that are thrown from your methods.

Sample Code

You can download the code for this sample at www.pdsa.com/downloads. Choose the category “PDSA Blogs”, then locate the sample Introduction to Unit Testing.

Testing is Not Just for Quality Assurance People

Testing Every developer needs to test their code, or have it tested by someone. I don’t know about you, but I am horrible at testing my own code. Does this mean that I do not need to test my code? Heck, no! It is always best if you do not rely on your end-user to test your code. This can end up with a very frustrated user, and your user can lose faith in your ability to get their project done. There are several ways you can get your code tested. This article explores a few of these methods for testing and talk about the advantages and disadvantages of each.

Why you should Test your Code

We all know that we need to test our code prior to putting it into production. Testing is your way of ensuring that the code you have written actually works as expected. But it is not enough to check that it works as expected, but also under varying circumstances, and with different inputs. For example, what if someone takes the database offline? Will your code recover gracefully from this exception? Does your code inform the user that there is a problem with the database connection in a friendly, easily-understood manner? All of these questions should be answered in the testing of your code. You need to simulate these exceptions so you can test your exception code.

Performing the act of testing often helps you improve the quality of your code. As you think about the various scenarios that can go wrong, you add additional code to handle these scenarios. This leads to your code being more robust and ultimately more maintainable and user-friendly. You will find that taking time to test your code makes you a better programmer in the long run. Your boss, and your end-users, will appreciate the extra effort.

Problems with the Develop/Test Cycle

There are a lot of disconnects between the development of the code and testing of code. In many cases there is too much code embedded in the user interface (UI). Too much code in the UI makes testing hard because the tools for testing user interfaces aren’t very robust. It is also hard to determine if all of the code in the UI has actually been tested. A tester has to know all of the inputs to give the UI to have it run all of the code.

This leads to yet another disconnect; there is too much communication required between a developer and the QA person. Sometimes a developer will forget to tell the QA person about a “special” case. In other cases, a QA person forgets to tell the developer about something that failed, so it does not get caught and ends up as another bug that, hopefully, will be found later.

Another problem is when a developer thinks they have fixed a bug, only to find out that the fix caused a bug in another part of the program. The QA department may not know to test that other part of the program which could mean a bug gets shipped to a customer. Or, the QA department thinks it affects other areas, so they end up doing a lot more regression testing than maybe they need to.

How to Test Your Code

There are many different methods used to test code. Here are some different methods you can use to ensure you are writing quality code.

  • Use a Quality Assurance (QA) person or company
  • Have your end-user test
  • Have a co-worker test
  • Write code to test your code

Of the above listed methods of testing, the first three involve humans, while the last one is a more automated approach. Let’s look at these different methods of testing code.

The Human Approach

Having a human test your code does have a lot of advantages. First off a human is going to be able to click on different buttons and test the UI very well. Having different people test your code can be helpful because each person may think of different things to test. In addition it will take less time up front to develop your software. 

But just as there are advantages to using humans for testing, there are also disadvantages. Testers find bugs, document them and push them back to you to re-code. After this, the tester has to go back and re-test. You will find this takes a lot more time in the long run. Many times prior to testing someone has to create records in a database, and afterwards get rid of tables, records, or files on disk. This is a very time-consuming and error-prone operation. You also find that the burn-out rate for QA people is very high. You frequently have a high turnover rate in this job function. So there are many down-sides to using humans to perform testing.

The Automated Approach

Instead of having a human do all the testing, you should start to use the great testing tools that are available in Visual Studio to create automated tests. Unit testing has become very prevalent in today’s professional software shops. Unit testing simply means you write a program, or most likely a series of programs to test each line of code you write to ensure that it operates properly under all circumstances.

While this sounds like a lot of work, and it can be more work up-front, you will more than make up that time by avoiding multiple regression tests by a human. You can automate the setup and tear down of databases, files, etc. With the correct architecture you can automate almost all the various inputs a human tester would have to enter by hand.

You will also save the time you normally eat up when you do your own testing by pressing F5 to start Visual Studio, wait for the compile process, click through a half dozen menus to finally get to the point where you want to start testing. As you know, this can sometimes take 15 seconds to a minute depending on how large your application is. Instead, you can run one or two tests in just a couple of seconds. This will add up in saving you many hours over the complete development cycle.

As you can see, there are many advantages to an automated approach over a human approach to testing. Automated tests are repeatable as opposed to having a human who might forget to test something. You will end up with more of your code tested because things won’t be forgotten. Because you will be forced to think of how to test your code while you are writing it, you will write better code. You will also save time on the setup and the tear down of the tests since these tasks can also be automated.

Of course, there are disadvantages to the automated approach as well. First of all, it does take more time up-front to develop these tests. Automated tests are only as good as the person that develops the tests. The tools to test user interfaces are not too great at this time without spending a fortune on third party testing tools. Of course, if you are using good N-Tier techniques, MVC, MVP, MVVM or similar design patterns, there should be very little UI for you to test anyway. 

Which Approach Should You Use?

The big question is this: do you use automated unit tests or do use a QA department? I still think you need a little of both. You want to get as many automated tests as you possibly can as this will save a lot of regression testing. Then the QA department can focus more on system testing, workflow and ensuring the correct data is flowing all the way through the application. The QA department can also focus on the UI features that are difficult to automate. A good mix of the two will go a long way toward making your applications much more robust and error free.

Architecting Your Code for Testing

As you are coding your application there are things you can do to prepare to take advantage of unit testing. Correctly architecting an application will do wonders for re-usability, readability, upgradeability, maintainability and testability. Take advantage of the design patterns that exist today such as MVC, MVP, MVVM or derivatives thereof. All of these patterns help you remove code from the user interface layer of your application. Removing code from the UI layer is this is the single best thing you can do to have a well architected, easily testable application.

Your UI code should strive to just call or bind to classes. Each class you write is where all the logic is contained for your application. Moving all application logic into classes, you take advantage of the various unit testing tools in Visual Studio. All of these classes should be combined into assemblies to aid not only in testing, but also in re-usability. 

Other techniques you should employ are to make your methods as small as possible.  A method should do one thing and one thing only. This makes testing that method easy as you most likely will only need to write one method to test that method. It is better to have many smaller methods and smaller tests, than one large method with lots of tests against that one method. One last technique is to use code generation tools for generating your CRUD layer. Create, Read, Update and Delete logic is employed in almost all business applications and is very standard code. There is no reason to hand-write this code with all of the tools available today to generate it. And, generated code is generally code you do not need to test. If the code generator is good, it will generate bullet proof code every time.

Visual Studio Testing Tools

Beginning with Visual Studio 2008, unit testing tools were added to almost all SKUs of Visual Studio. This means you do not need to purchase Team Foundation Server to be able to use unit testing. It also means you do not have to use NUnit or some other third-party application for unit testing. It is available to you right out of the box. Of course, the TFS version of Visual Studio has many more features, but for basic unit testing, you will find everything you need in the normal versions.

Summary

Unit testing is something every developer should employ as a part of their software development life cycle. Not only will help you improve the quality of your code, it will save you time and money in the long run. As you focus on architecting your applications for unit testing, you will find that your code will become re-usable, maintainable and more robust. Take some time to learn about the unit testing tools built-in to the Visual Studio suite of products and you will be on your way to better productivity.