6

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
  • 1
    " Should I make a mock of ..." nice pun :)
    – Peter G.
    Sep 9, 2015 at 13:16
  • I am already half way through a Python script called Scoff (Software Creation Of Functionalityless Files) Sep 9, 2015 at 13:49
  • Which, I now realize, useless, since Google Mocks comes with an excellent gen_mock.py script </reinvent_wheel> Sep 19, 2015 at 13:37
  • 3
    Ha ha! Look how ugly that header file is! ...oh, wait. That's not what you meant? Sep 22, 2015 at 15:21
  • Some spoilsport edited the original title :-( Jul 25, 2019 at 13:51

2 Answers 2

4
+50

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
  • I agree, although we may quibble over wording. Until I have proven the worth of unit testing, there will be no re-factoring, so no dependency injection. However, I can still make dummies, stubs, even if we don't want to call them mocks, of the public functions of b.cpp, whcih is how I will have to start. Sep 9, 2015 at 13:48
  • 1
    @Mawg Good luck with that. I am sure you will find that way of mocking classes quite cumbersome. Also, you will find writing unit tests, without refactoring, very difficult. Sep 9, 2015 at 13:51
  • 2
    Of course it will be difficult, but politics are politics and it is currently the only way forward. Sep 9, 2015 at 14:41
4

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.