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

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


Maybe we are not talking about the same chapter.  My fault.

cmocka lives with all the limitations of C when trying to bind a test-double. Options are link-time binding, function pointers or preprocessor substitution. I barely discussed preprocessor substitution in the book, but I have numerous articles on my blog.

cmocka is just C code. So it has no monopoly on being the one way to do mocking in C. IMO cmocka's advantage is it is small and written only in C. C-only has benefits and limitations too, which I discuss in the book. cmocka also does a few things in an odd way. For example, setup and teardown are not like setup and teardown in other xunit frameworks. I forget the details, but remember being surprised.

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 14:31, Frank Lorenz wrote:

Hi James,

are we talking about the same chapter?

Last sentence in first paragraph of chapter 9 ("Runtime-Bound Test
Doubles") is: "We will employ function pointers so
that we can test a function and replace it too, in the same test build."
That's what I am looking for, I think.

Your book helps me very much for getting deeper insight into effectively applying TDD to a legacy C project. I hope I will succeed with this task...

To come back on-topic: If you can mock objects with any framework and
use function pointers for run-time substitution, what is the specific
thing about cmocka? When I first read about cmocka my impression was
"this is the only approach to use mock objects when doing TDD in C". But
this does not seem to be the case. So what can you do with cmocka that
you can't do with other frameworks?

best regards,
Frank


Am 27.05.2014 19:06, schrieb James Grenning:
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 objectsAndreas Schneider <asn@xxxxxxxxxxxxxx>