Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Unit Testing in C++

Reply
Thread Tools

Unit Testing in C++

 
 
earthwormgaz
Guest
Posts: n/a
 
      06-24-2008
Hello,

I'm after doing some C++ unit testing, I'm using CppUnit. I like the
look of RudeMocks, but it doesn't work for Solaris/Sparc, so its no
good to me sadly.

So, I have class A, and it uses classes B and C. B and C have methods
A uses, but they're not virtual, and I don't want to hack the code so
that they are just to allow Unit Tests to work. This means that
inheriting from B and C to provide Mock classes is a non starter.

So, I've been trying to provide a mock implementation which is
basically a copy of B or C, but with the guts ripped out and swapped
for mock code. I've then tried to get the code for A, which is under
test, to include the mock versions of the classes headers it depends
on, and link to the objects built from the mock source.

The trouble is, A, B and C are all in the same directory. So, when A
does #include "B.h", it picks up the real version, even if I add the
include path to the mock header. That's because the current directory
takes precedence using VC++, it may well do with GCC and Suncc, which
I'm also using.

I've tried to get around this by not building an object file for class
A, but using A.obj which has already been built, but linking it
against my mock versions of B.obj and C.obj. This would work, except
that C.h defines C::~C(), and so A.obj ends up with a definition of
C::~C() in it, and I get multiply defined symbol link errors. I could
make sure all method definitions are in cpp files, but often having a
getter or setter inline is perfectly sensible.

How do people get around these issues of mocking out classes
effectively from a build system point of view?
 
Reply With Quote
 
 
 
 
anon
Guest
Posts: n/a
 
      06-24-2008
earthwormgaz wrote:
> Hello,
>
> I'm after doing some C++ unit testing, I'm using CppUnit. I like the
> look of RudeMocks, but it doesn't work for Solaris/Sparc, so its no
> good to me sadly.
>
> So, I have class A, and it uses classes B and C. B and C have methods
> A uses, but they're not virtual, and I don't want to hack the code so
> that they are just to allow Unit Tests to work. This means that
> inheriting from B and C to provide Mock classes is a non starter.
>
> So, I've been trying to provide a mock implementation which is
> basically a copy of B or C, but with the guts ripped out and swapped
> for mock code. I've then tried to get the code for A, which is under
> test, to include the mock versions of the classes headers it depends
> on, and link to the objects built from the mock source.
>
> The trouble is, A, B and C are all in the same directory. So, when A
> does #include "B.h", it picks up the real version, even if I add the
> include path to the mock header. That's because the current directory
> takes precedence using VC++, it may well do with GCC and Suncc, which
> I'm also using.
>


you can do this:

#ifdef USE_MOCK_CLASSES
#include "Bmode.h"
#else
#include "B.h"
#endif

Define USE_MOCK_CLASSES when you want to do the testing, that is, change
your make file to do it automatically


> I've tried to get around this by not building an object file for class
> A, but using A.obj which has already been built, but linking it
> against my mock versions of B.obj and C.obj. This would work, except
> that C.h defines C::~C(), and so A.obj ends up with a definition of
> C::~C() in it, and I get multiply defined symbol link errors. I could
> make sure all method definitions are in cpp files, but often having a
> getter or setter inline is perfectly sensible.
>
> How do people get around these issues of mocking out classes
> effectively from a build system point of view?

 
Reply With Quote
 
 
 
 
earthwormgaz
Guest
Posts: n/a
 
      06-24-2008
On 24 Jun, 13:19, anon <(E-Mail Removed)> wrote:
> earthwormgaz wrote:
> > Hello,

>
> > I'm after doing some C++ unit testing, I'm using CppUnit. I like the
> > look of RudeMocks, but it doesn't work for Solaris/Sparc, so its no
> > good to me sadly.

>
> > So, I have class A, and it uses classes B and C. B and C have methods
> > A uses, but they're not virtual, and I don't want to hack the code so
> > that they are just to allow Unit Tests to work. This means that
> > inheriting from B and C to provide Mock classes is a non starter.

>
> > So, I've been trying to provide a mock implementation which is
> > basically a copy of B or C, but with the guts ripped out and swapped
> > for mock code. I've then tried to get the code for A, which is under
> > test, to include the mock versions of the classes headers it depends
> > on, and link to the objects built from the mock source.

>
> > The trouble is, A, B and C are all in the same directory. So, when A
> > does #include "B.h", it picks up the real version, even if I add the
> > include path to the mock header. That's because the current directory
> > takes precedence using VC++, it may well do with GCC and Suncc, which
> > I'm also using.

>
> you can do this:
>
> #ifdef USE_MOCK_CLASSES
> #include "Bmode.h"
> #else
> #include "B.h"
> #endif
>
> Define USE_MOCK_CLASSES when you want to do the testing, that is, change
> your make file to do it automatically
>
> > I've tried to get around this by not building an object file for class
> > A, but using A.obj which has already been built, but linking it
> > against my mock versions of B.obj and C.obj. This would work, except
> > that C.h defines C::~C(), and so A.obj ends up with a definition of
> > C::~C() in it, and I get multiply defined symbol link errors. I could
> > make sure all method definitions are in cpp files, but often having a
> > getter or setter inline is perfectly sensible.

>
> > How do people get around these issues of mocking out classes
> > effectively from a build system point of view?

>
>


I'd rather not have to change the original source code just to
accommodate mocking for unit tests. Is that actually what most people
end up doing?

It seems a bit of an 'orrible fix to me.
 
Reply With Quote
 
Puppet_Sock
Guest
Posts: n/a
 
      06-24-2008
On Jun 24, 9:14*am, earthwormgaz <(E-Mail Removed)> wrote:
[snip]
> I'd rather not have to change the original source code just to
> accommodate mocking for unit tests. Is that actually what most people
> end up doing?


So, your plan is to do unit testing without writing any code?

Let us know how that works out.
Socks
 
Reply With Quote
 
earthwormgaz
Guest
Posts: n/a
 
      06-24-2008
On 24 Jun, 14:33, Puppet_Sock <(E-Mail Removed)> wrote:
> On Jun 24, 9:14*am, earthwormgaz <(E-Mail Removed)> wrote:
> [snip]
>
> > I'd rather not have to change the original source code just to
> > accommodate mocking for unit tests. Is that actually what most people
> > end up doing?

>
> So, your plan is to do unit testing without writing any code?
>
> Let us know how that works out.
> Socks


I'm expecting to write code, in the form of test code, and mock
objects. I'm hoping not to have to change the classes under test just
to test them.
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      06-24-2008
On Jun 24, 3:14 pm, earthwormgaz <(E-Mail Removed)> wrote:
> On 24 Jun, 13:19, anon <(E-Mail Removed)> wrote:
> > earthwormgaz wrote:


[...]
> > > The trouble is, A, B and C are all in the same directory.


And if you know the problem, you know the way to fix it.

> > > So, when A
> > > does #include "B.h", it picks up the real version, even if I add the
> > > include path to the mock header. That's because the current directory
> > > takes precedence using VC++, it may well do with GCC and Suncc, which
> > > I'm also using.


> > you can do this:


> > #ifdef USE_MOCK_CLASSES
> > #include "Bmode.h"
> > #else
> > #include "B.h"
> > #endif


> > Define USE_MOCK_CLASSES when you want to do the testing,
> > that is, change your make file to do it automatically


So you end up testing something different than what you deliver?
Not a good idea, by any means.

> > > I've tried to get around this by not building an object
> > > file for class A, but using A.obj which has already been
> > > built, but linking it against my mock versions of B.obj
> > > and C.obj. This would work, except that C.h defines
> > > C::~C(), and so A.obj ends up with a definition of C::~C()
> > > in it, and I get multiply defined symbol link errors. I
> > > could make sure all method definitions are in cpp files,
> > > but often having a getter or setter inline is perfectly
> > > sensible.


> > > How do people get around these issues of mocking out
> > > classes effectively from a build system point of view?


> I'd rather not have to change the original source code just to
> accommodate mocking for unit tests. Is that actually what most people
> end up doing?


> It seems a bit of an 'orrible fix to me.


It is.

It's not too clear to me what your deliverables are, but
generally, you should organize your directory structure so that
everything in a given directory can be tested together. If you
need a mock something, then that something should normally be
from a different directory, and not part of the code being
developed in the same directory.

If you need mock object (which you should avoid if
possible---but it isn't always possible on larger projects), you
should arrange for them at the start, putting them in a separate
directory. If the mock objects don't contain any templates or
inline functions, you use the standard header for it, and link
against a locally defined mock library. If B contains templates
or inline functions (both things to be avoided as much as
possible exactly for these sort of reasons), you're probably
stuck with having to compile against a different header file as
well (again, in the mock directory), but beware that this
seriously affects the reliability of your tests, in a negative
way.

To pick up the mock objects, of course, you just add the
appropriate -L (and -I, if you can't avoid it) in the compiler
command (before the other -L or -I).

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
earthwormgaz
Guest
Posts: n/a
 
      06-24-2008


James Kanze wrote:

> It's not too clear to me what your deliverables are, but
> generally, you should organize your directory structure so that
> everything in a given directory can be tested together. If you
> need a mock something, then that something should normally be
> from a different directory, and not part of the code being
> developed in the same directory.
>


Hmm, I'd come to think that I wanted to mock everything around the
class under test. You seem to be saying mock around the system that
includes the class under test, unless you have to do otherwise.

This is where the unit test/integration test line blurs ...

Say then that classes B and C interface into someLib:, you'd provide
a mock of D, and use test hooks from that?
 
Reply With Quote
 
Noah Roberts
Guest
Posts: n/a
 
      06-24-2008
earthwormgaz wrote:

> I'd rather not have to change the original source code just to
> accommodate mocking for unit tests. Is that actually what most people
> end up doing?


I try not to but sometimes it's the only way. It certainly points to
strong coupling when you have to trick your source into allowing a mock,
and maybe you want to do something about that, but sometimes that's just
the way it is.

You can't write perfect code. You shouldn't expect it and you shouldn't
try. Just do the best you can under the conditions you find yourself in.
 
Reply With Quote
 
Noah Roberts
Guest
Posts: n/a
 
      06-24-2008
earthwormgaz wrote:
>
> James Kanze wrote:
>
>> It's not too clear to me what your deliverables are, but
>> generally, you should organize your directory structure so that
>> everything in a given directory can be tested together. If you
>> need a mock something, then that something should normally be
>> from a different directory, and not part of the code being
>> developed in the same directory.
>>

>
> Hmm, I'd come to think that I wanted to mock everything around the
> class under test. You seem to be saying mock around the system that
> includes the class under test, unless you have to do otherwise.


I don't think the person you are replying to fully understands the
purpose of unit tests. You definitely do want to test each unit
individually; there should be a test for each public class at the least.
This often involves mock objects.
 
Reply With Quote
 
Greg Herlihy
Guest
Posts: n/a
 
      06-24-2008
On Jun 24, 4:43*am, earthwormgaz <(E-Mail Removed)> wrote:
>
> I've tried to get around this by not building an object file for class
> A, but using A.obj which has already been built, but linking it
> against my mock versions of B.obj and C.obj. This would work, except
> that C.h defines C::~C(), and so A.obj ends up with a definition of
> C::~C() in it, and I get multiply defined symbol link errors. I could
> make sure all method definitions are in cpp files, but often having a
> getter or setter inline is perfectly sensible.
>
> How do people get around these issues of mocking out classes
> effectively from a build system point of view?


It sounds like your problem could be fixed object by more carefully
controlling the visiblity of each module's symbols.

There should not be any problem with A.obj having linked in a copy of
C's destructor. The problem occurs when A.obj then -exports- C's
destructor (that it imported from C.obj) for other modules to link
against. So with A.obj and C.obj both claiming to have C's destructor,
the linker does not know which one to choose - and reports an error.

I'm assuming that each .obj file is configured to export of all of its
(global) symbols. In that case, I would reconfigure the .obj projects
to export no symbols by default. Next, I would then label (in the
source code), each of A's (public) methods with the appropriate
attribute for exporting (probably "dllexport" or similar). So, by
having A.obj, B.obj and C.obj exporting only the public functions of
their respective classes - there should be no more multiply-defined
symbols and the unit test modules and the program modules should link
together successfully.

Greg


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Webinar - Testing the Untestable - Unit Testing Dependencies andLegacy Code (in C++) Avi C Programming 0 06-11-2012 01:55 PM
[ANN] Webinar - Testing the Untestable - Unit Testing Dependenciesand Legacy Code in C++ Avi C++ 0 06-06-2012 11:25 AM
unit-profiling, similar to unit-testing Ulrich Eckhardt Python 6 11-18-2011 02:00 AM
Unit testing errors (testing the platform module) John Maclean Python 1 04-13-2010 02:11 PM
Test::Unit - Ruby Unit Testing Framework Questions Bill Mosteller Ruby 0 10-22-2009 02:02 PM



Advertisments