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

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


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 objects"James Grenning" <james@xxxxxxxxxxxx>