What strategies should I use to Mock unmanaged C++ classes for use by managed C++ unit tests?

917 views
Skip to first unread message

Sean

unread,
Jun 1, 2009, 12:53:53 PM6/1/09
to Google C++ Mocking Framework
Hi guys

I need some advice. I've been a long time user of JUnit, EasyMock and
code coverage as a Java developer. Now I find myself on a team using C
++ and Visual Studio 2008 Team System to develop a new product in
unmanaged C++. We have to use VS2008's in-built unit test facilities,
which means writing our unit tests in *managed* C++.

So, what strategies do you guys have when using Googlemock in managed C
++ unit test classes to test unmanaged C++ code in VS2008?

Managed C++ classes can only use unmanaged C++ classes that have been
packaged as static libs or DLLs:

C++ Unit Tests --->[binary boundary]--->C++ Production Code

Unfortunately VS2008's code coverage feature doesn't work for classes
in static libs. So we're going to package our production classes in
DLLs and export them, like this:

// IBankAccount.h

#ifdef MY_API
#define MY_API __declspec(dllexport)
#else
#define MY_API __declspec(dllimport)
#endif

class MY_API IBankAccount {
public:
virtual bool VerifyCustomerPin(long pin) = 0;
};


This also means our Mock classes have to packaged up in unmanaged C++
DLLs so our unit test projects can use them:

// BankAccountTests.cpp

#include "IBankAccount.h"

class MY_API MockBankAccount : public IBankAccount {
public:
MOCK_METHOD1(VerifyCustomerPin, bool(long pin));
};


At which point things fall apart. That MOCK_METHOD1(...) macro
produces in-line code that the Visual Studio compiler & linker don't
like in DLL class definitions.

Here's the output:

1>Compiling...
1>SimpleTests.cpp
1>c:\projects\cpp_unit_tests\mockexamples\automatedtellingmachinetest
\..\AutomatedTellingMachine\MockBankAccount.h(25) : warning C4251:
'MockBankAccount::gmock_VerifyCustomerPin_25' : class
'testing::internal::FunctionMocker<Function>' needs to have dll-
interface to be used by clients of class 'MockBankAccount'
1> with
1> [
1> Function=bool (long)
1> ]
1>Linking...
1>SimpleTests.obj : error LNK2028: unresolved token (0A0001B5)
"public: virtual __thiscall MockBankAccount::~MockBankAccount
(void)" (??1MockBankAccount@@$$FUAE@XZ) referenced in function
"public: void __clrcall
AutomatedTellingMachineTest::SimpleTests::shouldSuccessfullyVerifyCustomerPin
(void)" (?
shouldSuccessfullyVerifyCustomerPin@SimpleTests@AutomatedTellingMachineTest@@
$$FQ$AAMXXZ)
1>SimpleTests.obj : error LNK2028: unresolved token (0A0006DB)
"public: __thiscall MockBankAccount::MockBankAccount(void)" (??
0MockBankAccount@@$$FQAE@XZ) referenced in function "public: void
__clrcall
AutomatedTellingMachineTest::SimpleTests::shouldSuccessfullyVerifyCustomerPin
(void)" (?
shouldSuccessfullyVerifyCustomerPin@SimpleTests@AutomatedTellingMachineTest@@
$$FQ$AAMXXZ)
1>SimpleTests.obj : error LNK2019: unresolved external symbol "public:
virtual __thiscall MockBankAccount::~MockBankAccount(void)" (??
1MockBankAccount@@$$FUAE@XZ) referenced in function "public: void
__clrcall
AutomatedTellingMachineTest::SimpleTests::shouldSuccessfullyVerifyCustomerPin
(void)" (?
shouldSuccessfullyVerifyCustomerPin@SimpleTests@AutomatedTellingMachineTest@@
$$FQ$AAMXXZ)
1>SimpleTests.obj : error LNK2019: unresolved external symbol "public:
__thiscall MockBankAccount::MockBankAccount(void)" (??
0MockBankAccount@@$$FQAE@XZ) referenced in function "public: void
__clrcall
AutomatedTellingMachineTest::SimpleTests::shouldSuccessfullyVerifyCustomerPin
(void)" (?
shouldSuccessfullyVerifyCustomerPin@SimpleTests@AutomatedTellingMachineTest@@
$$FQ$AAMXXZ)


So what's to be done? If I have to jump through hoops (e.g. extra
Mock impl classes and projects) to get Googlemocks to work then they
will be a hard sell to the rest of my team.

All advice gratefully received.
--
Sean

Vlad Losev

unread,
Jun 1, 2009, 2:34:34 PM6/1/09
to Sean, Google C++ Mocking Framework
Hi Sean,

The linker messages indicate that your test module cannot locate the constructor and the destructor for MockBankAccount. Try explicitly defining them in the class:

   class MY_API MockBankAccount : public IBankAccount {
   public:
       MockBankAccount() {}
       ~MockBankAccount() {}

       MOCK_METHOD1(VerifyCustomerPin, bool(long pin));
   };

Your situation sounds strange since the compiler should be generating the default constructor and destructor automatically in the SimpleTests module. Maybe someone familiar with managed C++ code may chime in to explain.

Regards,
Vlad

Sean

unread,
Jun 1, 2009, 9:27:19 PM6/1/09
to Google C++ Mocking Framework
>> I need some advice. I've been a long time user of JUnit, EasyMock and
>> code coverage as a Java developer. Now I find myself on a team using C
>> ++ and Visual Studio 2008 Team System to develop a new product in
>> unmanaged C++. We have to use VS2008's in-built unit test facilities,
>> which means writing our unit tests in *managed* C++.
>
> Why? It wasn't designed for unmanaged code (I'm speaking as an original
> member of the VS Team System team, I was the dev lead for C++ Code
> Analysis). Have you considered using GTest instead?

Hi Jon

Well, most of the product is actually written in C#, and the company
has invested heavily in Visual Studio Team System, so VS2008's
in-built unit test stuff is perfect. The team leads want to be able
to make test lists, see coverage reports, manage continuous
integration builds etc. all from VSTS.

My team, however, is tasked with delivering a high performance
video/audio pipeline component for which unmanaged C++ has been chosen
for performance reasons and the fact that numerous C++ video codecs
are already available. So it made some kind of sense to place ALL the
testing & code coverage responsibilities in the lap of VSTS.

We don't mind packaging our unmanaged classes in C++ DLLs (and COM
interops for the C# GUIs) so VS2008's limited approach to C++ testing
didn't seem that big an impediment. Thereafter it seemed only a short
step to integrate Googlemock to complete the picture.

The Googlemock Wiki confidently states that it can be integrated with
any testing framework, so I embarked on integrating it with VS2008 :-)

Personally, I don't really care what testing & mocking frameworks we
use (so long as we use something!), but my hands are tied unless GTest
can be easily integrated with VSTS test lists and dashboard stuff..?

Thanks!
--
Sean

Zhanyong Wan (λx.x x)

unread,
Jun 2, 2009, 1:39:29 AM6/2/09
to Sean, Google C++ Mocking Framework
Hi Sean,

I don't have VS 2008 and thus cannot experiment with it.

On Mon, Jun 1, 2009 at 9:53 AM, Sean <sean...@gmail.com> wrote:

> 1>c:\projects\cpp_unit_tests\mockexamples\automatedtellingmachinetest
> \..\AutomatedTellingMachine\MockBankAccount.h(25) : warning C4251:
> 'MockBankAccount::gmock_VerifyCustomerPin_25' : class
> 'testing::internal::FunctionMocker<Function>' needs to have dll-
> interface to be used by clients of class 'MockBankAccount'

Not sure if this warning is essential, but it suggests that you may
need to export Google Mock's FunctionMocker class template (and
possibly other classes it depends on) as well. Could you try to add
MY_API to these class definitions?

> 1>        with
> 1>        [
> 1>            Function=bool (long)
> 1>        ]
> 1>Linking...
> 1>SimpleTests.obj : error LNK2028: unresolved token (0A0001B5)
> "public: virtual __thiscall MockBankAccount::~MockBankAccount

My guess is that VC cannot generate the destructor of MockBankAccount
because it needs to call the destructor of FunctionMocker, which is
not exported. Therefore fixing the above warning may fix this error
as well. The same for the errors below.

If this doesn't work or turns out too much work, here's another idea:

Instead of exporting your mock class definition from an unmanaged DLL,
could you write your test functions in the same DLL (and in unmanaged
C++) and then export the test functions? Your top-level tests can
still be written in managed C++ - they will simply call the real test
functions in the DLL.

--
Zhanyong

Sean

unread,
Jun 2, 2009, 7:34:06 AM6/2/09
to Google C++ Mocking Framework
On Jun 2, 6:39 am, Zhanyong Wan (λx.x x) <w...@google.com> wrote:
> My guess is that VC cannot generate the destructor of MockBankAccount
> because it needs to call the destructor of FunctionMocker, which is
> not exported.  

Hi Zhanyong

I think the underlying problem is that the header file for the
unmanaged Mock class cannot have any implementation code in it. If it
does, the *managed* unit test class won't build, presumably because
all managed-to-unmanaged implementation code must reside behind a
binary boundary. For example, the following code (which doesn't use
Googlemock at all) produces the same linker errors in my managed test
class:

#include "IBankAccount.h"
class MY_API MockBankAccount : public IBankAccount {
public:
bool VerifyCustomerPin(long pin) {return false;}
MockBankAccount(void) {};
virtual ~MockBankAccount(void) {};
};


So I may have to adopt your 2nd suggestion, namely delegating our
managed unit tests onto unmanaged DLL function exports.

Thanks!

--
Sean

Jared Wein

unread,
Jun 2, 2009, 1:10:06 PM6/2/09
to Google C++ Mocking Framework
Hi Sean,

The problem deals with the way that the class is declared. This is how
it is currently declared:

// IBankAccount.h
#ifdef MY_API
#define MY_API __declspec(dllexport)
#else
#define MY_API __declspec(dllimport)
#endif

class MY_API IBankAccount {
public:
virtual bool VerifyCustomerPin(long pin) = 0;
};

They way that the descspec(dllexport) works is that it will try to
export the whole class, including the compiler generated compiler and
destructor, which aren't defined.

To fix this, you would need to move the macro MY_API from the class
declaration to the function declaration, like so:

class IBankAccount {
public:
MY_API virtual bool VerifyCustomerPin(long pin) = 0;
};

You will need to do this for all exported methods.

Jared Wein

unread,
Jun 2, 2009, 1:50:21 PM6/2/09
to Google C++ Mocking Framework
Sorry, that should have read, "... the whole class, including the
constructor and destructor, which aren't defined ..."
Reply all
Reply to author
Forward
0 new messages