9

I want to understand the best way to design testable applications in C++, perhaps in comparison to C# (because its my background and great for testing)

I'm used to coding to interfaces, dependency injection, inversion of control frameworks, and mock objects. Since C# has a lot of different language features I'm not sure how much of the patterns should still apply. I also imagine C++'s unique features / limitations might lend to different testing strategies.

I've looked at unit testing frameworks, and I like Google Test, but it's also important to write my fresh code to be testable as possible.

  • Are there any opensource projects which could be recommended as C++ testing done right?
  • Any books or articles that go into this topic in greater detail?
  • Recommendations for additional frameworks / libraries

Thanks

Ryu
  • 8,641
  • 10
  • 65
  • 98

4 Answers4

6

I'm in the exact same situation myself, right now. Coming from a C# background, now I'm writing new (and expanding legacy) C++ applications.

I guess the shared background leaves us with common questions going forward. I was surprised how tightly coupled dependencies were to our classes in the legacy applications.

The concern, as you seem to have highlighted, is that maybe best practice in C# is not the best way in C++. After much research, some Stack Overflow questions of my own, and some prototyping, I've ended up with a C++ architecture that in many ways mirrors what I felt worked best in C#.

Here are the main principals I'm using:

  • Dependency injection

    Constructors for our classes take interfaces for dependencies that we might want to mock as parameters. In some cases, this meant writing wrappers for dependencies, like boost::filesystem, for example, which is mostly implemented in templated headers. Worth the small effort, in my opinion, as is more loosely couples us from libraries that may change or be swapped by us, and it allows us to unit test with mock implementations.

  • Test as you go!

    This should go without saying, but writing tests as you write the class allows you to sanity check your design in regards to testability. I don't care you test first, do TDD, or whatever you call it, my philosophy is just write your tests before you start consuming the class in your code base.

  • Google Test as our unit test framework

    So far, I've used Cxxtest (legacy apps) and Google Test. Google Test provides a lot of flexible options at execution time to determine what set of tests you run. We split our class naming convention out to UnitTest_xxxx and IntegrationTest_xxxx. Then at the command line, I can tell gtest to only run tests with one name, the other, or both. Then my build server can execute the long running tests over the whole test suite at night, but the unit tests at every check in. Cxxtest could do the same thing, but with more work, and is generally clunky for many reasons.

  • Google Mock for mock objects at test time

    The obvious benefit of dependency injection is using mocked objects during testing. One could simply write fake implementations of every interface, but Google Mock allows quick spin up of fake objects and provides the typical checks you would expect from a good .NET mocking framework like Moq or RhinoMock.

Evan
  • 2,441
  • 23
  • 36
2

I've used CPP Unit which is a port of JUnit. It's very easy to use and provides output in XML format which is great. As far as how to use it, you can check out the cookbook here.

bsimic
  • 926
  • 7
  • 15
1

In some occasions I've seen all the techniques you mention (coding to interfaces, dependency injection, inversion of control frameworks, and mock objects) being abused and ultimately making things harder. Although these techniques can be given a good use, sometimes I've seen them being preached as if they were the only road to quality. I disagree.

From my point of view, most important development technique for guaranteeing code quality in C++ is using Object Oriented Techniques such as Modularity, the Open-Closed principle, self-documentation, Command-Query Separation, etc.

In particular, two techniques which I find essential are Design by Contract (see the questions What is the best way of implementing assertion checking in C++? and Design by Contract in C++?) and Unit Testing (see related questions 1, 2, 3). For both of them you have reasonable tools in C++, as the linked questions show.

Community
  • 1
  • 1
Daniel Daranas
  • 22,454
  • 9
  • 63
  • 116
  • Dependency injection of interfaces is the primary tool that makes unit testing possible. – Dan Bryant May 03 '13 at 16:13
  • @DanBryant Well, C++ doesn't have interfaces, yet people do unit testing in it. – Daniel Daranas May 03 '13 at 16:15
  • 1
    Good counterpoints. I don't pretend that there is only one way to properly design and test. +1 for providing fresh ideas. Design by Contract is actually a practice that I've used with success if C#, and kind of forgot about in my new environment. Partially because .NET Code Contracts makes it so easy in C#. – Evan May 03 '13 at 16:48
  • 1
    I'm used to coding our contracts against an interface (in C++, this has boiled down to pure virtual declarations that we inherit from) so all implementations have a minimum set of expectations. http://codebetter.com/matthewpodwysocki/2008/11/14/net-code-contracts-and-tdd-are-complementary/. I do believe this is complimentary with TDD and a unit testing strategy in general, as the article highlights. Interesting answer in the linked DbC post, but one gap I see is that the class level is responsible for maintaing the contract, so differing implementations are not guaranteed to be consistent. – Evan May 03 '13 at 16:50
0

I can recommend UnitTest++ and AMOP for doing test-driven development. Both are very simple to set up and are very powerful. If you don't need all the features in Google Test, this is a good choice.

It may look like they're dated as they haven't been updated in a while, but I haven't had a single issue with them.

Pin
  • 3,746
  • 4
  • 26
  • 33