Should I also mock header files?

  softwareengineering

So, I am part of a very large project which has, as yet, no unit testing (shudder!) and I want to introduce it.

I plan on using Google Test and Google mocks.

The code is large and unwieldy and suffers from “header spaghetti”.

If I wish, for simplicities sake, to test only a.cpp which calls only a single function in b.cpp, then I can use Google Mock to generate a mock for b.cpp.

However, if I #include b.h in a.cpp and in my test suite, I find that b.h #includes a number of other headers, which in turn … in the end, I am #including hundreds of headers.

There will be no restructuring of header files (any time soon, if ever). I just have to live with that.

Until now, the code has only been built as a complete system, for an ARM processor, and now I want to build a.cpp plus b.cpp plus Google test to run on Linux.

I am having major problems as there are several hundred (!) compiler switches in the system build and I can’t easily see which are needed where, which are ARM only, what would replace them for Linux, etc.

Plus, some of them contain #defines which expand to function calls (especially from trace log, but also for others), and I don’t know where to find those in order to mock them.

Finally the question: how is this normally handled? Should I make a mock of b.h, which contains only what is needed by a.cpp?

If so, do I have to do it manually, or can Google Mock help in any way?

And, nope, the code won’t be restructured; at least not immediately, for fears of destabilizing it.

I really do not like the idea of pulling in the majority of headers in the system, but nor can I find an easy way to mock them 🙁

5

Since you are working on a legacy system (no unit tests), you are going to find it quite hard without modifying the code and refactoring.

The best use of mocks is with some kind of dependency injection. Injecting a mock object, instead of the real class. And not with injecting dependency by linking different object file (what you are trying to do).

The best way to start is to find what you can unit test, without using mocks. Then when you have time for refactoring, adjust the classes to somehow inject dependency and then use mocks.

3

The problem you are going to face is that the style of unit testing you have chosen, where everything outside a single file gets mocked, is actually useless when testing a code base not written to be compatible with it.

Your alternatives are:

  • exhaustively confirm that conclusion, and tell your team ‘I tried, but there is no point in unit testing’.
  • rewrite the code (which you have said you can’t do).
  • adopt a definition/style of unit testing that does add value given the existing code base

The latter would mean:

  • no mocking of anything except external hardware or timing interfaces
  • building tests incrementally upwards from the lowest level standalone components to the top level integrated systems.
  • using existing build and header files (because if some code doesn’t work with a given compiler flag, and that compiler flag is used, the test must fail).

In other words, for a legacy embedded system, there is no such thing as unit testing in the sense you get with higher level languages. Simply because you are always integrating with the compiler, if nothing else. And that compiler is typically such a sketchy mess of bugs, workarounds and undocumented limitations that you really want to be testing the exact code to be used, not an abstraction.

LEAVE A COMMENT