Moving Away from Exceptional Code

14 June, 2009 § Leave a comment

I once took a training course taught by Ron Jeffries and Chet Hendrickson on Test Driven Development. One of the participants in the course asked both Ron and Chet what are their recommendations on testing exceptional code paths. At first I didn’t think much of the question, since all the unit testing frameworks I’ve used have built-in ways to test exceptional code paths.

  • VSTS Unit Testing (.NET) has an attribute that you can put on a test to say that it is expecting an exception:
    [TestMethod, ExpectedException( typeof ( ApplicationException ) ) ]
    public void CreationOfFooWithNullParameterShouldThrowApplicationException()
    {
       var foo = new Foo( null ); //should throw an ApplicationException
    }
  • Google Test (C++) places a macro around the method call that is expecting an exception to be thrown:
     ASSERT_THROW(Foo(5), bar_exception);
  • unittest (Python) has a special assert to test if an exception was raised, similar to Google Test:
    def testsample(self):
       self.assertRaises(ValueError, random.sample, self.seq, 20)

The answer that Ron gave wasn’t expected, but led me to think about the way that we use exceptions within our codebase.

From what I remember, Ron said that he simply doesn’t test exceptional cases. How? He doesn’t have exceptional cases. He recommended using the Null Object pattern to get away from most of the exceptional cases.

Developers often have to pollute their code with checks to see if a value is null, like so:

XmlNode* userNode = xmlParser.GetNode( "user" );
return ( userNode == NULL ) ? "" : userNode->Text();

In the case above, the call to GetNode would search the XML document for a node with a tagName of “user”. If it finds it, it will return a pointer to the data. If not, then it will return NULL. This makes a lot of sense to developers, but it ruins some of the value of abstraction and good object-oriented programming.

First, any client who makes this call to GetNode has to know how GetNode works (they have to know that GetNode will return NULL if it can’t find the node). Second, there is a type check going on here, basically a runtime check to see if the type returned from GetNode is an actual XmlNode or if it is not.

One way to refactor away from this is to use the Null Object pattern. Martin Fowler talks about the Null Object pattern in his book, Refactoring: Improving the Design of Existing Code. In the section entitled, Introduce Null Object, there is a story told by Ron Jeffries describing how he has used Null Object to treat missing objects as actual objects.

The story goes over how if a record didn’t exist in the database, they would return an object like MissingPersonRecord, which would be derived from PersonRecord. All calls to methods on a MissingPersonRecord would simply return some default behavior and not complain. For example, if the MissingPersonRecord is asked for their name, they would respond with a blank string.

This allows any caller of the methods to not have to worry about missing people in the database. See how the code has changed:

XmlNode* userNode = xmlParser.GetNode( "user" );
return userNode->Text();

There is now no change in behavior if the node doesn’t exist, and there is also no knowledge about how GetNode works (besides the fact that the caller knows that it will never return NULL ;) ).

One library that I have used that follows this pattern is the TinyXml library in C++. When a caller asks for an XML node, there is no checking to see if that node really exists before making the call. This allows you to write code like so:

TiXmlNode* userNode = xmlParser.GetNode( "user" );
return userNode->FirstChild()->FirstChild()->Text();

A disadvantage to this is that when a Null Object has to be used, the error in the code can take a while to find. You may not know that there is a problem until a user object is displayed on screen without a required field like a “name”.

To solve this, you would have to debug and find the Null Object to determine why it is not a real object. Another approach could be to have the Null Object log a message in the Event Log when specific methods are called on it, but this can create too much noise, especially if you are using the Null Object pattern in the way that TinyXml does.

So, that is a little introduction on the Null Object pattern. To summarize, you can use the Null Object pattern to improve abstraction and polymorphism, and to reduce the lines of code per method.

Using Google Mock outside of Google Test

14 May, 2009 § 8 Comments

I’ve just finished getting an implementation going of MSTest with GMock, and I wanted to document all things neccessary to use GMock in a testing framework other than GTest.

To get GMock to build in VS2008, I had to install the Visual Studio 2008 Feature Pack. This was so I could get full TR1 support, specifically std::tr1::tuple. Other coworkers of mine haven’t needed to install the Feature Pack, though I presume that they didn’t need to because they had SP1 installed (which I thought I had installed). After installing the Feature Pack, I then had to reinstall SP1 due to some odd compiler errors that were occurring due to mismatched compiler versions.

Now some quick gotchas with GMock:

  • If you use the included gmock_gen.py script to generate your mocks from your pure abstract classes, then you will need to make sure that there are no default arguments in any of your mock’s methods.
  • When you add expectations to a mock, you should call VerifyAndClearExpectations at the end of your test method. You should assert that this method returns True. If you don’t include this method call, then your testing framework won’t be able to catch the GTest exceptions that will get thrown if the GMock’s expectations aren’t met.

Those are the only points I wanted to put out there at this point. When I run in to more bumps in the road I’ll be sure to publish them.

Unit testing MFC with MSTest

6 May, 2009 § 20 Comments

Visual Studio 2008 offers the built in ability to write unit tests in C# by creating a Test Project. This same feature applies to managed C++, otherwise known as C++/CLI. If you are working on a project in MFC and would like to get the same unit test integration that is built directly in to Visual Studio, there is a way. Here are the steps you will have to follow:

  1. Create a C++ Test project within your solution.
  2. Open up the Properties of the project and change the Common Language Runtime support from /clr:safe to /clr. This will allow you to execute code from both C++/CLI and simple C++.
  3. Set the project to link to MFC using a shared DLL. You cannot compile with both /clr and statically linking to MFC.
  4. Edit the test project’s dependencies and add a dependency on the MFC project that you would like to unit test.

You should be all good here, except for one large gotcha. The unit test project will have its own instance of CWinApp declared. If the MFC project that you would like to test against also has its own instance of CWinApp, then everything will get confused and the tests won’t start. To solve this, you will have to create a separate MFC DLL project and move your code to this project. Your test project should now have a dependency on this new MFC DLL project, and not your previous one. If you would still like your application to produce a single executable, just make sure that the previous project statically links against the MFC DLL that you have just created.

Let me know if you have any questions. I’ve spent the last couple days getting this scenario to work.

(I’m using GoogleMock with my unit tests, and I think that the combination of MSTest and GoogleMock is perfect. The integration with Visual Studio that MSTest provides, and the ease to make mocks with GoogleMock makes writing C++ unit tests a walk in the park. I should be putting up a simple tutorial on using GoogleMock in the future.)

MSTest fails to mention ignored tests

14 November, 2008 § Leave a comment

The other day I was writing some unit tests for a project I was working on. At the time, these tests contained some credentials that I both didn’t want to check-in and also didn’t want to break the build at a later date if I ever changed my password.

The test looked like this:

[Test]
public void TestLogIn()
{
  var username = "j.wein";
  var password = "123456";

  var authenticated = Directory.Authenticate( username, password );

  Assert.IsTrue( authenticated );
}

« Read the rest of this entry »

Where Am I?

You are currently browsing entries tagged with unit testing at JAWS.

Follow

Get every new post delivered to your Inbox.

Join 982 other followers