Freekshow

June 26, 2008

Unit testing with Visual Studio 2008 – Part 2

Filed under: Microsoft,Unit Testing — Freek Leemhuis @ 3:03 pm
Tags:

This is the second part of a series of blogpost on unit testing. Find the first part here.

In the first part we’ve introduced the MS Test framework, and I realise now that I’ve left out a few bits and pieces, so first off let me try to make amends. 

Initialize and Cleanup

Many times when running a test you’ll want to set up some conditions under which the test will run. After completion you’ll want to clean up these artifacts. Similarly to NUnit, where you’ll find attributes as [Setup] and [TearDown], MS Test has some attributes you can use to accomplish this.

To set up state before every test method in a test class, you can decorate a method with the [TestInitialize] attribute. Similarly, to clean up you can use the [TestCleanup] attribute.

For example, suppose you are testing some xml parsing routines. If you are testing agains some sample xml fragment, and it’s the same fragment for all your test methods in a class, you can set the fragment using the [TestInitialize] attribute:

private MyDataContext db; 

[TestInitialize()]
private void TestInit()  
{
     db = new MyDataContext(
        ConfigurationManager.ConnectionStrings["TestDatabase"].ConnectionString);
     db.Connection.Open(); 
}

 
Similarly, you can use the [TestCleanup()] attribute to dispose of any state.

[TestCleanup()]
private void WrapUp()
{
       db.Dispose();
       db = null;
}

Note: you only use a db connection setup like this when testing data access routines. For any other routines you do not really want the tests to hit the database.

So that’s pretty convenient: you don’t have to add the initialization code in the methods themselves. However, the opening and closing of the database will occur as many times as there are test methods in your test class.

You can use the [ClassInitialize] and [ClassCleanup] attributes for state changes that will execute only once for all test methods within a test class. However, for methods to use these attributes they must be static, which means that you can not use it to set properties on the instance of the test class.

Testing for exceptions

A lot of times I’ve seen developers using a try/catch block to test for exceptions. Joel for example has posted this little code snippet:

[TestMethod]
public void TestZipCodeNotNumericThrowsArgumentException()
{
       TransactionRequestInfo req = new TransactionRequestInfo();
       string testValue = "034JB";
       try
       {
           req.Zip = testValue;
           Assert.Fail("Exception not thrown.");
       }
       catch (ArgumentException aex)
       {
           Assert.IsTrue(true, "Exception Thrown Properly");
       }
}

You can see what he’s trying to do, and I’ve seen many a test use this approach. There is a better way: let’s rewrite this using the appropriate ExpectedException attribute:

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void TestZipCodeNotNumericThrowsArgumentException()
{
    TransactionRequestInfo req = new TransactionRequestInfo();
    string testValue = "034JB";
    req.Zip = testValue;
}

You can see it pays to investigate the full capabilities of the testing framework. Note that one would probably want to use a more specific exception than ArgumentException (InvalidZipcodeException?), but that’s for another post and another day.  

On cleanup and debugging

When dealing with databases, you might on occasion use a method with the TestInitialize attribute to verify preconditions in the database, and similar you have a cleanup routine to remove any artifacts. What happend to me on more than one occasion when starting with unit tests is that I would run tests under debugging, and when an expection occurred I would stop the debugging session. This however would prevent execution of any cleanup routine, and the state would not be properly reset before the following test run. Be sure to continue debugging to allow your cleanup code to execute!  

Keyboard Shortcuts

To wrap up the specifics of the MS Test frameworks, here’s a list of keyboard shortcuts to run your tests. The running of tests through the test windows is a bit cumbersome to navigate, so these keyboard combinations will come in handy:

CTRL + R, then press T
This runs the test(s) in the current scope. That is, it runs the current test method, all the tests in the current test class, or all the tests in the namespace, respectively.

CTRL + R, then press CTRL + T
This also runs the test(s) in the current scope, but under debugging.

CTRL + R, then press C
This runs all the tests in the current test class.

CTRL + R, then press A
This runs all the tests in the solution.

Resources

MSDN documentation on Unit Testing

Write Maintainable Unit Tests That Will Save You Time And Tears (MSDN article by Roy Osherove)

If you’re looking for a good book on unit testing, I can recommend Pragmatic Unit Testing in C# with NUnit , by Andrew Hunt and David Thomas. The authors use nUnit as the test framework, but the methods and practices apply regardless of what framework you use.

Roy Osherove shares his thoughts on unit testing and his upcoming book on The Art of Unit Testing/


Advertisement

5 Comments »

  1. Yes, as I mentioned in my post, I certainly have much to learn. One of the comments showed an alternate way to do this by creating a local ArgumentException variable and only populating it if the exception was properly thrown:

    [TestMethod]
    public void TestZipCodeNumericButGreaterThan99999()
    {
    TransactionRequestInfo req = new TransactionRequestInfo();
    string testValue = “58634789″;

    ArgumentException thrownException = null;
    try
    {
    req.Zip = testValue;
    }
    catch (ArgumentException aex)
    {
    thrownException = aex;
    }

    Assert.IsNotNull(thrownException, “Proper exception not thrown.”);
    }

    I liked this idea because it limits the method to a single Assertion, which seems like it would be ideal to me. I also like your approach, and I will definitely give it a spin, but what I do not like about it is that it is not readily apparent what the end result will/should be because there is NO Assertion statement.

    Thanks for the bits about initialize and cleanup, they will definitely come in handy

    Comment by joelcochran — June 27, 2008 @ 2:17 pm | Reply

  2. Hi Joel,
    We are all learning as we go along, and I’ve certainly had plenty of comments on the stuff I write, sometimes there’s no better code review than posting this stuff out into the open! So kudos to you for doing that.
    As for the alternative solution you’ve posted above, what if you get a different type of exception then ArgumentException? Will you not get a type conversion error in your catch block?
    Using the ExpectedException attribute, you don’t actually need an Assert, the test will fail if the expected exception is not thrown, and succeed if the specified exception is indeed thrown.

    Comment by Freek Leemhuis — June 30, 2008 @ 11:01 am | Reply

  3. Hi Freek,

    Thanks for all these useful information on unit testing. For a project which has already started, is that a way to add unit tests programmatically? What is the guideline to separate different tests into different test projects? One area that I want to know more is data-driven unit testing. Do you have information in that area?

    Thanks

    Comment by Peter — July 31, 2008 @ 12:58 am | Reply

  4. Hi Freek,

    I’m just getting back to this. It does make sense, and I guess it would be readily apparent to someone with more experience Unit Testing. You are probably right on the alternative approach, it creates more questions that need to be answered. One thing that I failed to mention that I really do like about your approach is its brevity. And now that I understand it a bit better, I’m sure I will be using this going forward.

    I do enjoy sharing code, and I never get defensive about it because there is almost always a better way to do things. Thanks to you as well for being willing to share your knowledge and techniques: the community makes us all better developers.

    Joel

    Comment by joelcochran — July 31, 2008 @ 2:25 pm | Reply

  5. [...] @ 11:20 am This is part 3 in a series of posts about unit testing using Visual Studio. Part 1 and part 2 focused mainly on the MS Test environment within Visual [...]

    Pingback by Unit testing part 3: Design for testability « Freekshow — September 3, 2008 @ 11:21 am | Reply


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

Gravatar
WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Theme: Rubric. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.