Saturday, October 4, 2008

Visual Studio's Unit Test Facility

Visual Studio's Unit Test Facility

I'm discussing a possible contract job in Bend, Oregon, and in those discussions, I learned that Microsoft Visual Studio has some built-in facilities for running unit tests--creating stubs for testing individual methods of a class, and then running those unit tests. Here's a description of it for the Visual Studio Team Test version.

Unfortunately, the Visual Studio Express Edition (which is free) doesn't have the unit test facilities in it. But I managed to come up with a reasonably good approximation--and I learned a bit more about C# along the way.

First of all, C# doesn't fully implement the # preprocessor facilities of C and C++. However, DEBUG is defined for the debug build, but not for the production build. So I put #if DEBUG...#endif wrappings around the unit test code. (The Debug.WriteLine method apparently does generate a small amount of compiled code in release versions if compiled--hence my enclosing it in #if DEBUG...#endif blocks--so that it doesn't get compiled except for the debug version.)

#if DEBUG
private void unitTestToolStripMenuItem_Click(object sender, EventArgs e)
{
// We only run these unit tests if DEBUG is set non-zero.
Eat1Test();
}

public void Eat1Test()
{
// EatWhiteSpace and Eat1 tests.
Debug.WriteLine("starting EatWhiteSpace and Eat1 unit tests");
String whiteSpaceBefore = " death and taxes";
int index;
index = Eat1(whiteSpaceBefore, 0, "death");
if(index != " death ".Length)
Debug.WriteLine("Eat1(whiteSpaceBefore, 0, \"death\") returned " + index);
index = EatWhiteSpace(whiteSpaceBefore, 0);
if (index != 1)
Debug.WriteLine("EatWhiteSpace(whiteSpaceBefore, 0) returned " + index);
String noWhiteSpaceBefore = "death and taxes";
index = Eat1(noWhiteSpaceBefore, 0, "death");
if (index != "death ".Length)
Debug.WriteLine("Eat1(noWhiteSpaceBefore, 0, \"death\") returned " + index);
String multipleWhiteSpacesAfter = "death and more taxes";
index = Eat1(multipleWhiteSpacesAfter, 0, "death");
if (index != "death ".Length)
Debug.WriteLine("Eat1(multipleWhiteSpacesBefore, 0, \"death\") returned " + index);
String nothingThere = "";
index = Eat1(nothingThere, 0, "death");
if (index != 0)
Debug.WriteLine("Eat1(nothingThere, 0, \"death\") returned " + index);
index = EatWhiteSpace(nothingThere, 0);
if (index != 0)
Debug.WriteLine("EatWhiteSpace(nothingThere, 0) returned " + index);
String onlyNewLineThere = "\n";
index = Eat1(onlyNewLineThere, 0, "death");
if (index != 1)
Debug.WriteLine("Eat1(onlyNewLineThere, 0, \"death\") returned " + index);
index = EatWhiteSpace(onlyNewLineThere, 0);
if (index != 1)
Debug.WriteLine("EatWhiteSpace(onlyNewLineThere, 0) returned " + index);
index = 5;
index = Eat1(onlyNewLineThere, index, "death");
if (index != -1)
Debug.WriteLine("Eat1(onlyNewLineThere, 5, \"death\") returned " + index);
index = EatWhiteSpace(onlyNewLineThere, 5);
if (index != -1)
Debug.WriteLine("EatWhiteSpace(onlyNewLineThere, 5) returned " + index);
Debug.WriteLine("ending EatWhiteSpace and Eat1 unit tests");
}
#endif
Pretty obviously, this is hardly a comprehensive test of even the Eat1 and EatWhiteSpace methods--but along the way, as I was writing the tests, I realized that there were some conditions that I hadn't considered when writing these methods--such as what happens if you pass EatWhiteSpace a starting index beyond the length of the string? So I improved the method to handle that error condition (which would otherwise cause an exception), and added a unit test for it.

Then I added a menu item "Unit Test" again wrapped inside of #if DEBUG...#else...#endif for the menu of the WebPageLinkAuditTool.

#if DEBUG
this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.webPageToAuditToolStripMenuItem,
this.pageSetupToolStripMenuItem,
this.printPreviewToolStripMenuItem,
this.printToolStripMenuItem,
this.exitToolStripMenuItem,
this.unitTestToolStripMenuItem});
#else
this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.webPageToAuditToolStripMenuItem,
this.pageSetupToolStripMenuItem,
this.printPreviewToolStripMenuItem,
this.printToolStripMenuItem,
this.exitToolStripMenuItem});
#endif

This isn't quite as elegant as the unit test facility built into the non-free versions of Visual Studio, but it isn't too terribly ugly.

No comments:

Post a Comment