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.

PDSA is now Fairway Technologies!

PDSA is now Fairway Technologies PDSA has merged with Fairway Technologies! This is definitely a case of one + one = three! When two great companies, that have made customer service a priority, come together, the end result is spectacular for our clients. With this merger, Fairway now has over 50 employees to help serve our customers in everything from Java to Oracle to SQL Server to .NET.

Stay tuned for more exciting news as we get our two companies completely integrated. In the meantime, it is business as usual at PDSA and at Fairway. All employees at PDSA and Fairway are very excited about our integration and will be sharing all resources to ensure a smooth transition.

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.