Unit Testing for Native Applications Using WinUnit

Introduction to WinUnit

Software development has changed a lot since the 70s. No longer is it simply called software development, it’s now called software engineering where the demand is not only for the product but for a product with quality. With .NET framework came a slew of tools to ensure code quality. Nothing got more limelight than NUnit, the tool for unit testing. Despite being in the industry for around 27 years, there hasn’t been an equivalent good offering for C++ programming to handle unit testing.

What is Unit Testing

Per Wikipedia, “unit testing” is defined as the method to ensure even the smallest testable portion of your software is working as expected. This small part can be as small as a function which determines if a number if even or odd; or it can be more complex.
Unit test authoring involves testing functionality in isolation. That ensures that even the smallest part is doing the job it is supposed to do. Imagine what would happen is NASA space shuttles did not use unit testing in their algorithms to determine if the launch speed was within the acceptable range or not.

Unit Testing Features Available for Programmers

There are a range of unit testing frameworks available for programmers http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks . Depending on the programming platform/language, developers/testers have a bunch of choice in unit testing tools/frameworks. However not all frameworks/tools are available in the language of choice. Case in point, NUnit (the ultra-popular does not have a simple equivalent in the native world.

Introducing WinUnit

WinUnit was authored by Microsoft engineer Maria Blees and is available for download as a free tool at http://winunit.codeplex.com/ .
WinUnit offers a NUnit type of unit testing experience. The WinUnit download contains an executable which run the test (available in x86 and x64), header files, logger extensibility library and macros for use inside of Microsoft Visual Studio.

How WinUnit Works

WinUnit works only on code which is refactored into a library. If the only entry point to your algorithm is to instantiate the UI of the application and then click a button, you have some work to do. You will have to move out the logic of your application to be tested into a DLL/lib file.

To create WinUnit test functions, you create a “.cpp” file. To start off, you use the macro BEGIN_TEST and provide it a test name. To check a criterion, WinUnit provides macros like WIN_ASSERT_EQUAL, WIN_ASSERT_TRUE, WIN_ASSERT_NOT_EQUAL, WIN_ASSERT_STRING_EQUAL, etc to check conditions. You then end your test with the macro END_TEST.

Once you have your test read, you compile your test file using the following command-line:

  cl.exe /EHsc /LD <WinunitTestFile.cpp>

Once your test file is compiled into a DLL, you then use the WinUnit.exe (from the WinUnit download) to run the test.

   <PathtoWinUnit>WinUnit.exe WinUnitTestFile.dll
   WinUnit will run the tests for you and report any failures as under
   Processing [WInUnitTestFile.dll]...
   (WinUnitTestFile)
   WinUnitTestFile.cpp(6): error : WIN_ASSERT_TRUE failed: "1 == 0".
   FAILED: DemoWinUnit.
    [WinUnitTestFile.dll] FAILED.  Tests run: 1; Failures: 1.
 

How to write efficient test code using WinUnit without polluting your source code.

Let us have a hands-on example of how to write efficient unit testing code using WinUnit. For our case, let us assume we have an extremely complex function which determines if a provided number is even or odd. It returns 0 if the input was even and 1 if the input was off.

Here is how the sample code looks.

  // Listing 1 - EvenOrOdd.h
  class EvenOddDeterminator
  {

  	public:
  		EvenOddDeterminator();
  		~EvenOddDeterminator();
  		int IsItEven(int input);
  };

  // Listing 2 - EvenOrOdd.cpp
   #include "EvenOrOdd.h"
  EvenOddDeterminator::EvenOddDeterminator()
  {
  }
  EvenOddDeterminator::~EvenOddDeterminator()
  {
  }
  int EvenOddDeterminator::IsItEven(int input)
  {

  		if ((input % 2) != 0)
  			return 0;
  		else
  			return -1;

  }

As you can see above, we have a bug where we calculate where the input value is even or not.
To see how to write a WinUnit test, let’s take a look at the listing 3 below.

  // Listing 3 - DemoWinUnit.cpp
  #include "..\WinUnit-1.2.0909.1\Include\winunit.h" // TODO Set the correct path to WinUnit.h on your machine
  #include "EvenOrOdd.cpp"
  BEGIN_TEST(DemoWinUnit)
  {
     EvenOddDeterminator c ;
     WIN_ASSERT_FALSE (c.IsItEven(3) == 0, _T("You should not see this error message."));
  }
  END_TEST


  BEGIN_TEST(DemoWinUnit2)
  {
     EvenOddDeterminator c ;
     WIN_ASSERT_TRUE(c.IsItEven(2) == 0, _T("You should not see this error message."));
  }
  END_TEST

If we look closer at the DemoWinUnit.cpp code, we find that we have two tests – DemoWinUnit and DemoWinUnit2. The first test, DemoWinUnit, checks that when we pass 3, an odd number, to the function, we should get not get zero, which we ascertain by using the macro WIN_ASSERT_FALSE which means that this condition should not pass.

More by Author

Must Read