Testing is an increasingly important part of a software development workflow. In many cases, it is insufficient to test a program simply by running it and trying it out – as the scope of the project gets more involved, it becomes increasingly necessary to be able to test individual components of the code on a structured basis. If you’re a C++ developer and are interested in unit testing, you’ll want to be aware of Visual Studio’s unit testing tools. This post goes through just that, and is part of a series aimed at new users to Visual Studio.
This blog post goes over the following concepts:
- Setting Up Unit Testing
- The Microsoft Native C++ Unit Test Framework
- Using the Test Explorer to Run Tests in the IDE
- Determining Unit Test Code Coverage
Setting Up Unit Testing
The easiest and most organized way to set up unit tests is to create a separate project in Visual Studio for your tests. You can create as many test projects as you want in a solution and connect them to any number of other Visual Studio projects in that solution that contain the code you want to test. Assuming you already have some code that you want to test, simply follow these steps to get yourself set up:
- Right-click your solution and choose Add > New > Project. Click the Visual C++ category, and choose the Test sub-category. Select Native Unit Test Project, give the project a descriptive name, and then click OK.
- Visual Studio will create a new project containing unit tests, with all dependencies to the native test framework already set up. The next thing to do is to add references to any projects that will be tested. Right-click the unit test project and choose Add > Reference…
- Check any projects that you want to unit test from your test project, and then press OK.
Your unit testing project can now access your project(s) under test. You can now start writing tests, as long as you add #include statements for the headers you want to access.
The Microsoft Native C++ Unit Test Framework
Visual Studio ships with a native C++ test framework that you can use to write your unit tests. The framework defines a series of macros to provide simplified syntax.
If you followed the steps in the previous procedure, you should have a unit test project set up along with your main code. Open unittest1.cpp in your test project and look at the starting code provided:
Right from the start, you’ll notice that dependencies have already been set up to the test framework, so you can get to work writing your tests. Assuming you connected your test project to your project(s) under test via Add > Reference earlier, you can simply add the #include statements for the header files of the code you want to test.
Tests can be organized by using the TEST_CLASS and TEST_METHOD macros, which perform exactly the functions you’d expect. A TEST_CLASS is a collection of related TEST_METHODS, and each TEST_METHOD contains a test. You can name your TEST_CLASS and TEST_METHOD anything you want in the brackets. It’s a good idea to use descriptive names that make it easy to identify each test/test group individually later.
Let’s try writing some basic asserts. At the TODO comment, write:
This is a basic equality assert which compares two expressions. The first expression holds the expected value, the second holds the item you are testing. For the Assert to pass, both sides must evaluate to the same result. In this trivial example, the test will always pass. You can also test for values you don’t want your expression to evaluate to, like this:
Here, for the test to pass, the two expressions must not evaluate to the same result. While this kind of assert is less common, you may find it useful for verifying edge cases where you want to avoid a specific behavior from occurring.
There are several other Assert functions that you can try. Simply type Assert:: and let IntelliSense provide the full list to take a look. Quick Info tooltips appear for each Assert as you make a selection in the list, providing more context on their format and function. You can find a full reference of features in the Microsoft C++ native framework on MSDN.
Using the Test Explorer to Run Tests in the IDE
With Visual Studio, you’re not restricted to running unit tests in the command line. The Text Explorer window in Visual Studio provides a simple interface to run, debug, and parallelize test execution.
This is a straightforward process. Once you connect your test project to your project(s) under test, add some #include directives in the file containing your unit tests to the code under test, and write some Asserts, you can simply run a full build. Test Explorer will then discover all your unit tests and populate itself with them.
NOTE: In .NET, a feature called Live Unit Testing is available. This feature is not currently supported in C++, so unit tests are discovered and executed only after you run builds.
To run your unit tests, simply click the Run All link in the Test Explorer. This will build your project (though this process is skipped if the project is already up to date) then run all your tests. The Test Explorer indicates the passing tests with a checkmark and the failing tests with an X. A summary of execution results is provided at the bottom of the window. You can click on any failing unit test to see why it failed, including any exceptions that may have been thrown. Execution times for each unit test are also provided. For realistic test execution times, test in the Release solution configuration rather than Debug, which will provide faster runtimes which are more approximate to your shipped application.
Determining Unit Test Code Coverage
If you are using Visual Studio Enterprise, you can run code coverage on your unit tests. Assuming you have unit tests already set up for your project, this is as simple as going to Test > Analyze Code Coverage in the main Visual Studio menu at the top of the IDE. This opens the Code Coverage Results window which summarizes code coverage data for your tests.
NOTE: There is a known issue where Code Coverage will not work in C++ unless /DEBUG:FULL is selected as the debugging configuration. By default, the configuration is set to /DEBUG:FASTLINK instead. You can switch to /DEBUG:FULL by doing the following:
- Right-click the test project and choose Properties.
- Go to Linker > Debugging > Generate Debug Info.
- Set the option to Generate Debug Information optimized for sharing and publishing (/DEBUG:FULL).
The Code Coverage Results window provides an option called Show Code Coverage Coloring, which colors the code based on whether it’s covered or not.
Code coverage is counted in blocks, with a block being a piece of code with exactly one entry and exit point. If a block is passed through at least once, it is considered covered.
For more information on C++ unit testing, including some more advanced topics, check out the following MSDN articles: