[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Fundamental question: How to resolve dependencies with mock objects


Hi Frank

I hope the book is helping. Thanks for buying it! Chapter 9 uses link-time substitution. The one drawback to link-time substitution is that the binding of the code under test to its service happens once per build. So it may lead you to many test builds. Gcc linker wrapping or function pointers are solutions to that problem.

James

--------------------------------------------------------------------------------------------
James Grenning                  Author of TDD for Embedded C
www.wingman-sw.com              http://pragprog.com/titles/jgade/
www.wingman-sw.com/blog
www.twitter.com/jwgrenning

On 27 May 2014, at 9:44, wp1186628-frank wrote:

Hi James,

looks like I wrote the mail to early. Chapter 9 of your book covers this
topic...

best regards,
Frank

wp1186628-frank <frank@xxxxxxxxxxxxxxxx> hat am 27. Mai 2014 um 08:50
geschrieben:

Hi James, hi Jakub,

thanks for the feedback. I misunderstood that I do not need wrapping to mock
objects.

James: At the moment I read your book, currently at chapter 8. Up to now, you only describe how to replace interaction to Hardware / OS, i.e. mock external modules that are not part of your project and you do not need to unit test at
all.
But if I have a big system (with complex dependencies between its like typical for legacy code) and you want to unit test all the modules, I'm not really sure how to handle this. If I do use function pointers like you describe I fear ending up with a really complex and hard to understand test
system, continously switching between fake and real implementation.

More concrete, a first step I want to take is to implement Unit Tests for a Model-View-Controller implementation (in C). If I want to test each of the three modules seperately (M, V and C), I will need flexiblity to change between fake and real implementation for each of the three. So is the only way to do this "function pointer thing" to achieve this? Is cmocka the right framework for this or are there frameworks available that can do this nicely?

best regards,
Frank




> > James Grenning <james@xxxxxxxxxxxx> hat am 21. Mai 2014 um 15:32
> > geschrieben:


Markdown settings messed with my example code. Here it is again

int (current_foo)(char c) = 0;

int _fakefoo(char* c)
{
if (currentfoo)
return currentfoo(c);

return 42;

}

On 21 May 2014, at 7:47, James Grenning wrote:

   > > >
You might want to implement _fakefoo with a function pointer. This
way you can swap the implementation at runtime

   int (current_foo)(char c) = 0;

   int _fakefoo(char* c)
   {
   if (currentfoo)
   return currentfoo(c);

   return 42;

   }


   ---------------------------------------------

   James Grenning Author of TDD for Embedded C
   <http://www.wingman-sw.com>
   http://pragprog.com/titles/jgade/
   <http://www.wingman-sw.com/blog>

   <http://www.twitter.com/jwgrenning>

   On 21 May 2014, at 7:27, Jakub Hrozek wrote:

       > > > >
       Hi,

       mock and wrap are two different things. You can mock a
function
without the wrap trick and vice versa. For instance, you can
mock a
function like the cmocka example illustrates by providing the
full
       function prototype and returning the previously prepared
return code:

http://git.cryptomilk.org/projects/cmocka.git/tree/example/customerdatabase_test.c#n38

The wrapping is a linker feature that allows you to trick the
linker
into calling wrapfoo() instead of foo(). You can always call
the
"real" foo if you like, by calling _realfoo(). This might be
useful
       to check if foo() was called in the program under test for
instance.
       In SSSD we have something like:

       bool wasfoocalled;

       _realfoo(); /* You need the declaration */

       _wrapfoo()
       {
       wasfoocalled = true; /* Let the test driver know foo was
called /
       _realfoo(); / Call the original foo function */
       }

       You can even control whether to call the real foo or some
mocked
       version based on parameter you pass with willreturn in
advance. Here
       is some example from SSSD:

https://git.fedorahosted.org/cgit/sssd.git/tree/src/tests/cmocka/testnss_srv.c#n89

       I hope this helps.

       On Wed, May 21, 2014 at 1:48 PM, Frank Lorenz
lorenz-frank@xxxxxx <mailto:lorenz-frank@xxxxxx> wrote:

           > > > > >
           Hi,

           starting to use unit tests for an existing project
(embedded C), I currently
           try to use cmocka for this.
           I have a lot of dependencies (e.g. to hardware) and
interfaces to other
devices that let me think I require mock objects to do a
"simple simulation"
           of hardware/interfaces for unit tests.
So I started to integrate cmocka and now have a lack of
basic understanding
           of the concept:

           As far as I understand, I need to implement a wrapper
function for every
function I want to mock. As an example, for a mock of a
function int
foo(char* c) I write a function int _wrapfoo ( char* c )
and give
           the option "--wrap=foo to the linker.

           My question is:
If I want to implement unit tests for two modules A and
B, and I want to
           have a mock version of B for unit test of A and a mock
version of A for unit
           test of B -- how to implement this?
Because when I implement mock versions of all functions
of A and of B and
           tell the linker to use these "wrappers" instead of the
real functions, then
           my unit test executable will only contain the mock
versions of all the
functions. The "real" implementation of A and B will not
be linked into the
           executable and therefore cannot be tested.
           Or do I miss something?

           best regards,
           Frank

       > > > >
   > > >
> >





Follow-Ups:
Re: Fundamental question: How to resolve dependencies with mock objectsFrank Lorenz <lorenz-frank@xxxxxx>