Ask a question about testing static function inside a module

772 views
Skip to first unread message

Rex Wang

unread,
Aug 2, 2012, 1:54:08 AM8/2/12
to cppu...@googlegroups.com
Hi,

We are doing our development work in C language, we have splitted the whole system into several modules(each module is represented by a .c source file and its header file), one module provide several interfaces for other modules to use, but most of time, a module doesn't only consist of those public interfaces, it also contains some private functions(static function in C), my question is that how to do UT for these static functions?
and what's more, are there some graceful ways to mock these static functions in order to test the public functions?

Thanks for your time and thanks for any help in advance. :-) 

Wang Peng

Bas Vodde

unread,
Aug 2, 2012, 3:19:47 AM8/2/12
to cppu...@googlegroups.com

Hi Wang Peng,

Uhm, will you be able to access these private functions via the public ones?

And… why would you want to mock out the static private functions?

Thanks!

Bas

Rex Wang

unread,
Aug 2, 2012, 3:35:32 AM8/2/12
to cppu...@googlegroups.com
Hi, Bas

thanks for your quick response. :-)

yes, actually, inside a module, those private functions are only used by the public ones inside that module.
but when testing those public ones, I want to mock those private functions to test each branch of the public ones.

besides this, I think even in C++, the private functions still needs UT, so how is these UT work be done in the project written in C++? can you please give me some suggestions?

Wang Peng

Bas Vodde

unread,
Aug 2, 2012, 3:37:17 AM8/2/12
to cppu...@googlegroups.com

Hiya,

> yes, actually, inside a module, those private functions are only used by the public ones inside that module.
> but when testing those public ones, I want to mock those private functions to test each branch of the public ones.
>
> besides this, I think even in C++, the private functions still needs UT, so how is these UT work be done in the project written in C++? can you please give me some suggestions?

Yes, usually you test them through the public interface :)

In unit testing, usually you don't write one test for one method but for one "piece of functionality". Therefore, you usually access the private methods via the public interface. Therefore, usually you don't need to mock the private methods, unless they do something harmful…

Do they do something harmful?

Bas

Rex Wang

unread,
Aug 2, 2012, 3:45:11 AM8/2/12
to cppu...@googlegroups.com
Hi,

I can't understand the 'harmful' exactly :-(
but what if they do things harmful? what should I do for such conditions?

Wang Peng

Terry Yin

unread,
Aug 2, 2012, 4:45:30 AM8/2/12
to cppu...@googlegroups.com
Hi Rax,

Follow this flow of thinking please:
1.If you have a strong urge to test a private function (with a good reason), it means this function should not be a private function.
2. So just make it public. If making it public bothers you, that means ...
3. The function doesn't belong there! It should be in some other module, or a new module should be created to take that part of responsibility, where it make sense to make this function public.

This also work when you have to replace (stub) a private function. E.g. when the private function does harmful things.

Harmful things can be: it talks to file system, it reboots the computer, it uses static variable, etc, etc.

br, Terry
--
-terry
-------------------------
Blog: http://terryyin.blogbus.com/
twitter: http://twitter.com/terryyin

Rex Wang

unread,
Aug 2, 2012, 5:02:01 AM8/2/12
to cppu...@googlegroups.com
Hi, Terry

Thank you very much for your explanation.
I will check the design of my project, maybe it's still not small enough, and maybe there's something wrong with the module division.


Wang Peng

Bas Vodde

unread,
Aug 2, 2012, 6:13:44 AM8/2/12
to cppu...@googlegroups.com

Hiya,

I think Terry already mentioned what harmful means :)

Usually, harmful is that it controls something external, such as database, filesystem, hardware, network, or stuff like that…

You don't want that in a unit test as it makes it slow and brittle. If they don't do anything harmful, then you can just test them via a public interface.

Bas

James Grenning

unread,
Aug 2, 2012, 8:20:02 AM8/2/12
to cppu...@googlegroups.com
I agree with Bas and Terry's advice.

Sometimes in a legacy situation, access to the statics might be need to get the code under test with minimal touching. One thing you can do is include the legacy C file in the test file. Now all statics are available for test. Faking them will be a problem, unless you convert some toe function pointers. In the long run, a design improvement is better, but you might need this to get the legacy code under test to start the refactoring preocess.

thanks, James

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

Terry Yin

unread,
Aug 2, 2012, 7:39:34 PM8/2/12
to cppu...@googlegroups.com
Hi James,

Great idea to #include "production_code_with_static.h"

But you will get duplicated symbols for those non-static ones, right? How do you avoid that? C++ namespace? ... no, namespace is not going to work ...

br, Terry

James Grenning

unread,
Aug 2, 2012, 8:06:37 PM8/2/12
to cppu...@googlegroups.com
I wish it was my idea.  I learned it from a client.  It's a handy trick; good for legacy code; with the limitation you mentioned.  You can only do it once in a executable.

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

Knut Aksel Røysland

unread,
Aug 3, 2012, 3:26:31 PM8/3/12
to cppu...@googlegroups.com
Hi Wang Peng,

I fully agree with the advices given to you by others on this list. If
you really need to mock those static functions, they belong in a
separate module, where they serve as that module's API.

If you found out that your static functions are in fact "harmful", you
could try to refactor the harmfulness out of them, without moving them
from their current location.

I interpret "harmful" as having communication (I/O) with an external
entity, without allowing the client to control what this external entity
is. The issue also concerns input like reading files, the system clock,
or a random number generator. Anything that makes the function have
unavoidable side-effects or non-deterministic behavior.

For instance, the following function is "harmful":

int harmful(const char * name)
{
return fprintf(stdout, "Hello %s\n", name);
}

while this one is not:

int harmless(FILE * stream, const char * name)
{
return fprintf(stream, "Hello %s\n", name);
}

The function harmful() is hard-wired to "stdout". Breaking this wiring
requires tricks like link-stubbing fprintf(), assigning "stdout" to
something else, or maybe doing symbol replacement with the preprocessor.
Otherwise, this function _will_ print its stuff to your terminal when
being tested, and you will have to redirect "stdout" to somewhere else,
on the outside of your test-process, to pick up the printed string and
check that harmful() behaved correctly.

On the other hand, harmless() lets the client determine where to send
the output. Your production code will pass "stdout" as argument, while
your tests pass some alternative mock FILE stream, e.g. one created by
fmemopen() or open_memstream(), which can then be inspected in-memory by
the test case after the call to harmless().

In my experience, software architecture quality goes up as the
percentage of harmful code goes down, due to increased modularity (less
coupling). Ultimately, your program contains only one harmful function,
main(), leaving all other code easily testable since it allows explicit
control over all its I/O collaborators.

In Haskell, the difference between harmful and harmless is considered so
important that it is built into the language itself. It is referred to
as "purity". The type-system ensures that pure (i.e. "harmless") code
cannot possibly call impure (i.e. "harmful") code. Personally, I have
never used Haskell for anything serious. However, I have found the
"purity" perspective to be very valuable and have brought it back with
me when I work on C/C++ code. It goes hand in hand with testability.

--
Thanks,
Knut Aksel R�ysland

On 08/02/2012 09:45 AM, Rex Wang wrote:
> Hi,
>
> I can't understand the 'harmful' exactly :-(
> but what if they do things harmful? what should I do for such conditions?
>
> Wang Peng
>
> On Thu, Aug 2, 2012 at 3:37 PM, Bas Vodde <ba...@odd-e.com
> <mailto:ba...@odd-e.com>> wrote:
>
>
> Hiya,
>
> > yes, actually, inside a module, those private functions are only
> used by the public ones inside that module.
> > but when testing those public ones, I want to mock those private
> functions to test each branch of the public ones.
> >
> > besides this, I think even in C++, the private functions still
> needs UT, so how is these UT work be done in the project written in
> C++? can you please give me some suggestions?
>
> Yes, usually you test them through the public interface :)
>
> In unit testing, usually you don't write one test for one method but
> for one "piece of functionality". Therefore, you usually access the
> private methods via the public interface. Therefore, usually you
> don't need to mock the private methods, unless they do something
> harmful�
>
> Do they do something harmful?
>
> Bas
>
> >
> > Wang Peng
> >
> > On Thu, Aug 2, 2012 at 3:19 PM, Bas Vodde <ba...@odd-e.com
> <mailto:ba...@odd-e.com>> wrote:
> >
> > Hi Wang Peng,
> >
> > Uhm, will you be able to access these private functions via the
> public ones?
> >
> > And� why would you want to mock out the static private functions?
> >
> > Thanks!
> >
> > Bas
> >
> > On 2 Aug, 2012, at 1:54 PM, Rex Wang <nuyi...@gmail.com

Rex Wang

unread,
Aug 6, 2012, 4:52:50 AM8/6/12
to cppu...@googlegroups.com
hi,

Bas, Terry, James and Knut, thank you very much for your great suggestions. they are precious to me. :-)

Wang Peng

On Sat, Aug 4, 2012 at 3:26 AM, Knut Aksel Røysland <knu...@gmail.com> wrote:
Hi Wang Peng,

I fully agree with the advices given to you by others on this list. If you really need to mock those static functions, they belong in a separate module, where they serve as that module's API.

If you found out that your static functions are in fact "harmful", you could try to refactor the harmfulness out of them, without moving them from their current location.

I interpret "harmful" as having communication (I/O) with an external entity, without allowing the client to control what this external entity is. The issue also concerns input like reading files, the system clock, or a random number generator. Anything that makes the function have unavoidable side-effects or non-deterministic behavior.

For instance, the following function is "harmful":

int harmful(const char * name)
{
    return fprintf(stdout, "Hello %s\n", name);
}

while this one is not:

int harmless(FILE * stream, const char * name)
{
    return fprintf(stream, "Hello %s\n", name);
}

The function harmful() is hard-wired to "stdout". Breaking this wiring requires tricks like link-stubbing fprintf(), assigning "stdout" to something else, or maybe doing symbol replacement with the preprocessor. Otherwise, this function _will_ print its stuff to your terminal when being tested, and you will have to redirect "stdout" to somewhere else, on the outside of your test-process, to pick up the printed string and check that harmful() behaved correctly.

On the other hand, harmless() lets the client determine where to send the output. Your production code will pass "stdout" as argument, while your tests pass some alternative mock FILE stream, e.g. one created by fmemopen() or open_memstream(), which can then be inspected in-memory by the test case after the call to harmless().

In my experience, software architecture quality goes up as the percentage of harmful code goes down, due to increased modularity (less coupling). Ultimately, your program contains only one harmful function, main(), leaving all other code easily testable since it allows explicit control over all its I/O collaborators.

In Haskell, the difference between harmful and harmless is considered so important that it is built into the language itself. It is referred to as "purity". The type-system ensures that pure (i.e. "harmless") code cannot possibly call impure (i.e. "harmful") code. Personally, I have never used Haskell for anything serious. However, I have found the "purity" perspective to be very valuable and have brought it back with me when I work on C/C++ code. It goes hand in hand with testability.


--
Thanks,
Knut Aksel Røysland


On 08/02/2012 09:45 AM, Rex Wang wrote:
Hi,

I can't understand the 'harmful' exactly :-(
but what if they do things harmful? what should I do for such conditions?

Wang Peng

On Thu, Aug 2, 2012 at 3:37 PM, Bas Vodde <ba...@odd-e.com
<mailto:ba...@odd-e.com>> wrote:


    Hiya,

     > yes, actually, inside a module, those private functions are only
    used by the public ones inside that module.
     > but when testing those public ones, I want to mock those private
    functions to test each branch of the public ones.
     >
     > besides this, I think even in C++, the private functions still
    needs UT, so how is these UT work be done in the project written in
    C++? can you please give me some suggestions?

    Yes, usually you test them through the public interface :)

    In unit testing, usually you don't write one test for one method but
    for one "piece of functionality". Therefore, you usually access the
    private methods via the public interface. Therefore, usually you
    don't need to mock the private methods, unless they do something
    harmful…


    Do they do something harmful?

    Bas

     >
     > Wang Peng
     >
     > On Thu, Aug 2, 2012 at 3:19 PM, Bas Vodde <ba...@odd-e.com
    <mailto:ba...@odd-e.com>> wrote:
     >
     > Hi Wang Peng,
     >
     > Uhm, will you be able to access these private functions via the
    public ones?
     >
     > And… why would you want to mock out the static private functions?

     >
     > Thanks!
     >
     > Bas
     >
     > On 2 Aug, 2012, at 1:54 PM, Rex Wang <nuyi...@gmail.com
Reply all
Reply to author
Forward
0 new messages