Click here to Skip to main content
Click here to Skip to main content

How to use NUnit to test native C++ code

, 18 Jan 2010
Rate this:
Please Sign up or sign in to vote.
Because NUnit is designed to unit test managed code, it does not lend itself to test unmanaged C++ code as easily as for C#, until now!

Introduction

There are several ways to test native (unmanaged) C++ code using NUnit. Because NUnit is designed to unit test managed code, it does not lend itself to test unmanaged C++ code as easily as for C#. Until now.

Background

When testing C# code, in most cases, no changes have to be made to the code before it can be tested with NUnit. That is, as long as the C# code is accessible via a public interface to a DLL, nothing more needs to be done in order to access the code from an NUnit test DLL. The developer creates the NUnit test DLL and calls the code under test.

With C++, however, additional steps need to be taken. For example:

  • Expose the C++ class as a CoClass so that it can be instantiated using COM.
  • or

  • Recompile the component as Managed C++ (C++/CLI).

In addition to the extra work which is not required for a C# component, these options have their own drawbacks. In the first case, unless the C++ class was already designed this way, it will likely be non-trivial to convert a C++ class to be accessible through COM. In the second case, if the C++ class is in a native code module, an extra step is needed to recompile it as managed code just for testing, ensuring the development tool supports this (VC6 doesn't), and the code needs to be modified to expose the class as a managed class, among other issues.

Proposal

The proposal is to use a seldom used feature in C++, which is to export the native C++ class under test from the DLL, then use the C++ Interop (implicit P/Invoke) feature to call the class from the test DLL, which is written in C++/CLI.

The advantage of this solution is that it does not require a special version of the production DLL to be created just for testing. We still need to export the C++ class, but that's no different than if the production class was a private C# class. NUnit won't be able call that either, so this is a general issue with NUnit in that code under test has to be externally accessible. Furthermore, it's also assumed that the code under test is in a DLL, which is what we would have to do with C# code.

C++'isms

In C#, the only way to reuse code is to put that code in a DLL. C++, however, also lets us create static link libraries (traditional .lib), and also code can be shared by simply #include'ing it. The solution described in this article does not address testing code in a static link library or shared C++ header files.

Solution details

Let's say that you have a C++ DLL that has the following class that you want to test:

class CChecksum
{
public:
    DWORD GetChecksum( LPBYTE buf, LONG len );
};

The first step is to export the class so that it can be called from outside the DLL. Add __declspec(dllexport) after the class keyword, so the resulting code looks like this:

class __declspec(dllexport) CChecksum
{
public:
    DWORD GetChecksum( LPBYTE buf, LONG len );
};

Next, create the NUnit test DLL in C++/CLI. It may look like this:

using namespace NUnit::Framework;
...
[TestFixture]
public ref class CChecksumTester
{
public:
    [Test]
    void GetChecksumTest()
    {
        char* buf = "This is a test";
        CChecksum c;
        DWORD v = c.GetChecksum( (LPBYTE)buf, strlen(buf) );
        Assert::AreEqual(v,552367893);
    }
};

You can now load this the test DLL from NUnit. You'll have to do the usual C++ things necessary to call a DLL, such as have the test DLL link to the implicit library (.lib) of the DLL being tested, and the test code needs to #include the header file of the class.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Kenneth Kasajian

United States United States
My interests mostly revolve around making machines do work for people. I'm a computer programmer, software architect, development manager, program manager and a computer programmer. I said programmer twice because I believe you need to be able to do the work yourself if you're going to direct others. I started my career creating software for abstract art, followed by work in embedded systems and HMI. In the 90s I created a successful product called Visual DLL and helped develop the Sales Force Automation product, Arsenal. I've often been involved in online communities, creating games, utilities, and collaboration software. I'm passionate about agile requirements management, acceptance testing through executable specification, and anything that will make developers more productive. My current role is Principal Scientist where I get to work on different technologies with an awesome team, to solve real-world practical problems. I'm Armenian, so talking is in my nature -- if you see me online or offline, say hi and we'll geek out about the latest tools and libraries. If you learned something cool recently (and you should if you're a lifelong learner), then I'd like to hear about it.
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
GeneralIt works for me, but still feel C# has much better support for TDD Pinmemberfourretout123-Jan-10 11:19 
GeneralRe: It works for me, but still feel C# has much better support for TDD PinmemberKenneth Kasajian24-Jan-10 20:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 18 Jan 2010
Article Copyright 2008 by Kenneth Kasajian
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid