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

How to use NUnit to test native C++ code

By , 18 Jan 2010
 

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
Other
United States United States
Member
My interests mostly revolve around making machines do work for people. I'm a computer programmer, software architect, development manager and program manager. 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. Currently I'm a Program Manager, where I get to tell others what needs to get done. Smile | :)

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionLinking Errosmemberfor study13 Feb '13 - 19:15 
Hello Kenneth,
This is really a good article for understanding NUnit to test in C++.Now I need your help and suggestion to resolve the issues I receive while working on similar scenarios.
 
I have a project called "Application" which has methods declared using
__declspec(dllexport)
This Application project has reference of 3rd party static libs and headers.
Application uses API declared from these headers.
 
Now when I add TestApplication project and call method to test from Application I am getting linking errors.
I get following error message for a method which uses single API.
Error	1	error LNK2019: unresolved external symbol ApplicationWindowActivate referenced in function "void __cdecl GeometryAppActivateWindow(int)" (?GeometryAppActivateWindow@@YAXH@Z)	F:\AppStaticLib\TestAppStaticLib\AppStaticLib.lib(AppStaticLib.obj)	TestAppStaticLib
 
In Error message
ApplicationWindowActivate
is the API from 3rd party headers ,
GeometryAppActivateWindow
is the methos in my application which is calling this API and AppStaticLib is my static library application and TestAppStaticLib is testing application.
 
Here is my method defination for which I would like to add test..
__declspec (dllexport) void GeometryAppActivateWindow(int windowId)
{
    int result = ApplicationWindowActivate(windowId);
}
 

Now looking at kind of configuration it seems to be issue with use of 3rd party API's and headers. So can you please suggest some methods to create a NUnit testing DLL with such static library.
 
Thanks
GeneralIt works for me, but still feel C# has much better support for TDDmemberfourretout123 Jan '10 - 11:19 
@PatLeCat: The length or the article is pretty irrelevant, what matters is the quality. A long article that is not helpful is twice rubbish, once just for not adding any value and secondly for wasting more time reading it.
 
@the author:
 
Thanks. After a couple of minor tweaks it worked great for me.
 
I used to link my C++ libs to a C# test project to run there my tests on NUnit and Rhino Mocks. I'll give it a go in the way you do it in your article and see how it goes.
 
BTW the comment:
 
"In C#, the only way to reuse code is to put that code in a DLL."
 
is a tiny bit narrow.
 
I gave it 4 because it does what it says on the label and without rumbling for hours as many articles do around here.
GeneralRe: It works for me, but still feel C# has much better support for TDDmemberKenneth Kasajian24 Jan '10 - 20:43 
Thanks.
 
What is the issue with the statement regarding reuse of code having to do with being in a DLL for C#? I'd like to fix that, if it's wrong, so what do you mean exactly?
 
What I meant to say is that, in C++, there are several ways one can reference code outside of a project other than putting in a DLL, and that's to use a static library, or to use header files (ala STL, ATL, BOOST)
 
ken@kasajian.com / www.kasajian.com

GeneralMy vote of 2memberPatLeCat19 Jan '10 - 4:54 
Too short an article.
GeneralRe: My vote of 2memberKenneth Kasajian24 Jan '10 - 20:45 
Sorry.
 
It took me longer to make the article shorter, so that people wouldn't have to read more than they have to, to get the essence of the method. If something is missing, or unclear, I can fix that -- let me know what.
 
ken@kasajian.com / www.kasajian.com

GeneralVisual studio 2005 cannot load the CRC projectmemberMember 24964069 Sep '08 - 1:34 
The following error has occurred during XML parsing:
 
File: D:\test\test_nunit\Checksum\CRC\CRC.vcproj
Line: 6
Column: 2
Error Message:
The element 'VisualStudioUserFile' is used but not declared in the DTD/Schema.
The file 'D:\test\test_nunit\Checksum\CRC\CRC.vcproj' has failed to load.
 
Please upload a new correct zip file.
 
Regards,
Bert
GeneralRe: Visual studio 2005 cannot load the CRC projectmemberKenneth Kasajian18 Jan '10 - 16:07 
Please try the new version just uploaded. Should work with Visual Studio 2005
 
ken@kasajian.com / www.kasajian.com

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 18 Jan 2010
Article Copyright 2008 by Kenneth Kasajian
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid