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

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


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 objectswp1186628-frank <frank@xxxxxxxxxxxxxxxx>