Monday, 17 November 2008

Using NUnit with native C++

NUnit was designed to be used with managed apps. So what?

All you need to do in order to test native code is create a C++/CLI project to host the test files. To link the test project to the native C++ project, simply add a configuration to the solution and call it ReleaseUnitTests for instance. This configuration will build the native C++ project as a static library as opposed to an executable. The C++/CLI test project links to this library and can call into any public method of the native project.

Job done! Who needs cppunit?

Detailed steps:

  1. Install NUnit.
  2. In Visual Studio Pro, create a native C++ project and call it CatHouse
  3. Add a class called Cat with a public method void Feed()
  4. Add another project to the solution: choose Visual C++ > CLR > Class Library and call it CatHouseTests. This will create a mixed assembly containing both native and managed code.
    Add a C++ managed class called CatTest. Declare it public because we want it to be a managed type that can be seen by Nunit. Add a public method called TestFeed().
  5. Open CatHouseTests project properties, go to Common Properties > References and add the nunit.framework.dl assembly.
  6. In CatTests.h, add the line using namespace NUnit::Framework.
  7. Now you can add the [TestFixture] and [Test] attributes to the class and test method declarations respectively.
  8. By default the CatHouse project has a Debug and Release configurations. Add a new one called ReleaseUnitTests: in Build > Configuration Manager in the Active Solution Configuration drop-down, select New. In the dialog, type ReleaseUnitTests and in Copy settings from choose Release. Click OK. Now all projects have a configuration called ReleaseUnitTests.
    Using Configuration Manager, ensure that the Debug and Release solution configurations build CatHouse only and not CatHouseTests. Ensure that ReleaseUnitTests builds both CatHouse and CatHouseTests, both having project configuration ReleaseUnitTests.
  9. Open the properties of project CatHouse and in Configuration Properties > General, select Configuration ReleaseUnitTests. Change configuration type to Static Lib (that will make it possible to link all the content with the test program).
  10. Make CatHouseTests link to the .lib generated by CatHouse. In Project Properties of CatHouseTests, go to Common Properties > Add New Reference > Projects > CatHouse.
  11. Add a #include "Cat.h" in CatTest.cpp and change the project properties so that it knows where to find the include.
  12. In the TestFeed() method, instantiate a Cat object on the native stack and call its Feed() method.
  13. Build the solution in Release mode then in ReleaseUnitTests mode.
  14. In the NUnit GUI type Ctrl O, select the CatHouseTests.dll. The TestFeed test should appear in the tree view.


Anonymous said...

In step 8. the correct C++ statement needed is In CatTests.h, add the line:

using namespace NUnit::Framework;

N and U must both be capitalized, and the line ends with a semicolon.

With that single change, I have successfully been able to get a C++ project integrated with NUnit 2.4.6

adactuslatem said...

I keep getting unresolved external symbol when trying to build this sample project when trying to create a cat object and call its feed method.

Cat* cat = new Cat();

Matt said...

I tried it and found the same problem under VS2010. That looks like a new behaviour of Visual Studio 2010: to allow CatHouseTests to link with the CatHouse library, you have to go Common Properties > Framework and References > Add New Reference and select the CatHouse project. Before 2010 setting up a project dependency between CatHouseTests and CatHouse was enough.
Hope that helps.