Virtual Developer Workshop: Containerized Development with Docker
In an earlier article, we saw how developers can use WinUnit for authoring unit test cases for their code. While the article demonstrated the use of WinUnit as a command line tool, most of the developers use Microsoft Visual Studio for their coding. Let us understand how we can integrate WinUnit into the Microsoft Visual Studio IDE. We will also explore some tips and tricks on using WinUnit and what are the scenarios where WinUnit should be used.
Integrating WinUnit with Microsoft Visual Studio
To get started, you want to make sure that your have the WinUnit include files in your project include path. You can set that in the Project Properties of your C++ Library project. Go to Configuration Properties -> C/C++ and add the path to the WinUnit header files to the "Additional Include Directories" setting.
Now that you have WinUnit header files in your include path, you can easily create WinUnit tests and refer to the WinUnit macros without running into unresolved references in your C++ project.
To add the facility of running WinUnit tests after you build your binary, you need to configure WinUnit as one of the available external tools in Microsoft Visual Studio and then set it up as a post-build step.
Navigate to the External Tools window by going to the Tools menu and selecting External Tools (Tools -> External Tools) Here, click "Add" to add the information about WinUnit as visible from the screenshot below.
Add "WinUnit" as the title and in the "command" filed, make sure you have the full path to the
winunit.exe of the desired bitness. For arguments, make you that you miss out on the enclosing quotes.
Check the "Use Output windows" and uncheck "close on exit" and click OK to add WinUnit to the external tools list.
At this point, you can now invoke WinUnit from the Tools menu itself.
Now, if you are a super-developer, you can setup the execution of the unit tests as part of the build step as soon as the build is done.
For this, go to the Project Properties Page and select Configuration Properties -> Build-Events ->Post-Build Event and set the "command line" property to the full path to winunit.exe followed by "$(TargetPath)". Make sure to include the quotes.
For my machine the command line looks like "
C:\Users\vipul\Documents\articles\Unit testing for native applications using WinUnit\WinUnit-1.2.0909.1\Bin\x64\WinUnit.exe" "$(TargetPath)"
Now that you have WinUnit as part of the build step, as soon as you build your application, WinUnit executes as the last part of the build process.
WinUnit Assert Macros
The most useful macros I have encountered are the following. There are more macros besides these.
|WIN_ASSERT_EQUAL||To check equality|
|WIN_ASSERT_NOT_EQUAL||To check inequality|
|WIN_ASSERT_TRUE||To check if condition is true|
|WIN_ASSER_FALSE||To check if condition is false|
|WIN_ASSERT_THROWS||To check if expression throws C++ exception|
|WIN_ASSERT_NULL||To check if expression is NULL|
|WIN_ASSERT_NOT_NULL||To check if expression is not NULL|
When the assert fails, it is indicative of a test failure. These Assert macros are simply a wrapper of Win32 Assert API but also include the file and line number and sometimes a string representation of the failing expression.
If you want to log something informational in a test, you can use WIN_TRACE macro.
WinUnit Class Members & File List
WinUnit contains 3 different classes
- WinUnit::Assert class similar to .NET's Assert class
- WinUnit::AssertException class
- WinUnit::Environment class.
WinUnit is contained in 2 header files -
WinUnitLogger.h. The function prototypes in
WinUnitLogger.h are supposed to be implemented by a custom logger if custom logging is desired on top of WinUnit.
Advanced Usage of WinUnit
WinUnit also provides a facility called "fixtures", which offers a way to "Setup" and "Cleanup" before and after the test. To create a fixture, you need to define new sections in your test called "SETUP" and "TEARDOWN".
Also you have to now start your test using
BEGIN_TESTF instead of
BEGIN_TEST. You also pass in the fixture name as the second argument following the test name.
You then end the test with
END_TESTF instead of
Guidelines for using WinUnit
To keep things simple, do not create more than one test file per class. Also, from my personal experience, it keeps code sane by having at least one unit test per method. More tests per function are OK as long as they don't repeat the same code path. Since WinUnit relies on C++ exceptions to do its magic, make sure to compile your test dll with the /EHsc flag.
Choose the appropriate
WIN_ASSERT macro for your scenario. There are string versions of the macros available for string comparisons too.
Use fixtures (discussed above) to ensure your setup and cleanup are done properly.
Ensure you have proper names for the Unit test so that it becomes very easy to understand what unit test condition failed to speed you finding root cause. Ditto for the informational message printed in some cases, when the assertion fails.