11

Should you design your code to make testing easier? And if so how to design c++ code so that it is easy to test.

  • How do you apply dependency-injection in c++?
  • Should I implement the classes using a pure interface class as the base in order to simplify the creation of fake test objects?
    • That would force me into making a lot of virtual methods. Will that affect performance?
  • What else should I think about when designing for testability in c++?
Joakim Karlsson
  • 1,112
  • 1
  • 15
  • 27
  • Designing for testability really is a must have. However you also have to realize that only the 'boundary' should be testable in stand-alone fashion, it is perfectly reasonable for internal components to depend on each others and not to be tested in isolation. – Matthieu M. Nov 05 '09 at 15:13
  • You might be interested in this [stack-exchange proposal](http://area51.stackexchange.com/proposals/11464/code-review?referrer=aWNm_PdciyFqjFW8CUacGw2 "code review"). It's almost ready to begin beta, just needs a few more. – greatwolf Jan 19 '11 at 04:46

4 Answers4

9

Should I implement the classes using a pure interface class as the base in order to simplify the creation of fake test objects?

  • That would force me into making a lot of virtual methods. Will that affect performance?

A workaround I often use is to templatize the class instead of hiding it behind an interface. Then I can pass test/mock objects as template parameters when testing, and the real objects otherwise. That way, the performance hit of virtual functions is avoided.

Edit
Ok, a simple example:

With OOP and interfaces, you might write a function such as this:

void Foo(IBar& someBar) { ... }

This function takes a parameter which implements the IBar interface, and does something with it. If you want to pass in a dummy mock implementation, you simply write a mock object which inherits from IBar and pass that to Foo. Simple and straightforward.

But you can achieve the same thing with templates:

template <typename BarType>
void Foo(BarType& someBar) { ... }

... and that's it. The body of Foo can be pretty much unchanged. As long as the type passed to the function exposes all the members we need, it'll work, without having to formally inherit from an interface class, and without the overhead of virtual functions and runtime polymorphism.

Community
  • 1
  • 1
jalf
  • 243,077
  • 51
  • 345
  • 550
  • Where can I read more on how templatizing classes? Is there a pattern describing this? – Joakim Karlsson Nov 05 '09 at 15:08
  • Why do You want a pattern for everything?? jalf has shown you an idea to leave inheritance (virtual/polymorphism) alone and use instead the C++ templates (generic programming). Giving generic mock (template code) would cover "all" possible types You would ever use (with one function, instead many "virtual methods"). – bua Nov 05 '09 at 15:13
  • 3
    Of course template may make compile-time dependencies harder since their implementation goes into the header. – Matthieu M. Nov 05 '09 at 15:14
  • No I don't mean that I need a pattern. I just want to see an example of what he means. I don't understand what jalf means just from the text in his answer. – Joakim Karlsson Nov 05 '09 at 15:19
  • 2
    @Matthieu M: The implementation may not have to go in the header. Keep in mind that the actual production code will only ever instantiate the template with one set of types (the real, non-mock, non-test ones). So the definition may only need to be visible in one translation unit. And your tests could then perhaps include the .cpp directly. Your test code may get a bit hackish as a result, but that may be a worthwhile tradeoff - Unit tests don't have to be super elegant code. – jalf Nov 10 '09 at 13:36
5

Don't design too much up from the start, then write a test, then make it pass, but not more than that. Keep your functions very short. Look what you've done and refactor it. If you're going to write a comment, better put the code in question to a separate function with a good name.

And don't spend too much time thinking of patterns, that's a lot of science and little outcome, just write a test first and keep your code simple, then, surprisingly you don't need to write tests for it, you've done it already. And your code works.

Dmitry
  • 6,590
  • 2
  • 26
  • 19
  • 1
    "If you're going to write a comment, better put the code in question to a separate function with a good name" This is very good advice. – Steven Keith Nov 28 '09 at 14:27
3

Maximum cohesion and minimum coupling.

This will make your life easier with testing.

bua
  • 4,761
  • 1
  • 26
  • 32
0

I think prime concern should be ...

  1. Achieving Functionalities
  2. Code Extensiblity
  3. Code Resuablity
  4. Code Maintainability
BenMorel
  • 34,448
  • 50
  • 182
  • 322
Ashish
  • 8,441
  • 12
  • 55
  • 92