views:

410

answers:

7

Unit testing with C/C++: What do you teach people who either did not do unit testing before or come from Java/Junit?

What is the single most important lesson / thing to remember/ practice from your point of view that saves a lot of time or stress (especially regarding C/C++)?

+8  A: 
  1. Unit tests have to run automatically on every checkin (or, unit tests that are written then forgotten are not unit tests).
  2. Before fixing a bug, write a unit test to expose it (it should fail). Then fix the bug and rejoice as the test turns green.
  3. It's OK to sacrifice a bit of "beauty" of a class for easier testing (like provide public methods that should not really be public, but help your testing/mocking).
ripper234
I disagree with 1. All UT should be run automatically during the night build, because they usually take a lot of time. Before every check in you should run UT only for your module.
m_pGladiator
3. Is also wrong - make UT classes friends and they will see everything
m_pGladiator
m_pGladiator:"A UT is not a UT by definition if it takes longer than 1/10 of a second to run.", paraphrased from Working Effectively with Legacy Code). Hence it would be ok to run it automatically on every commit.
David Holm
I also disagree with 3. You can inspect the inners of the class without sacrificing its design, for instance declaring in the tested class a friend observer class that would exist only in the UT.
Fabio Ceconello
+7  A: 
Gishu
+2  A: 

I'd like to rephrase ripper234 and add some more rules:

  1. Every module (usually DLL project) should have separate UT project. All UT classes should be friends to all the DLL classes they need to access private methods/members from.
  2. If you want to change the module - first change the UT. Make sure both the DLL and its UT compile, link and the UT run without crashes and failures before check in. There is no need to run all UT for all modules before each check in - this is a waste of time.
  3. All UT should be automatically rebuild in the nightly build along with all DLLs. All UT and modules should compile and link during the build.
  4. All UT should be automatically run after the night build succeeds and the results should be summarized.
  5. The summary with all UT results should be posted to the developers and if there are any failures or crashes they should be corrected ASAP.
m_pGladiator
+1  A: 

Single most important lesson: A test is better than no test.

graham.reeds
Unless the test is broken, of course, in which case you're shipping on false premises.
Johann Gerell
In fact I think 1 test for a class is more important than 100 tests. The first test is always the hardest, especially with legacy code, as it forces you to break the dependencies around the class so that you can get it under test in the first place.
Len Holgate
+1  A: 

A unit test case should only test one thing.

I see it much more often in C/C++ compared to C# and Java that unit test cases test entire workflows.

Perhaps it is because most C/C++ xUnit frameworks require several steps to register a testcase, so the temptation to just add a few lines to an existing testcase when adding a new feature is higher.

Rasmus Faber
I agree, BUT, I also like to see 'unit tests' which test object A plugged in to object B, etc, rather than ONLY tests which test object B with mocks of object A. I realise that these are more 'integration tests', but they can also be very useful.
Len Holgate
No one prohibits you from having integration tests, too. You just should not be calling them unit tests - not even 'unit tests'. Call them integration tests and do not mix them with your unit tests.
Rasmus Faber
+2  A: 

In the case of dealing with legacy code base with no tests, you will most probably start (as I had to) with functional tests that use a unit test framework for implementation. Don't be alarmed - your code is so interconnected that it's probably impossible to write proper unit tests. Don't be complacent, either - once functional tests are in place, you need to refactor so that true unit tests are possible. Your code will be better for it!

Arkadiy
+3  A: 

I'm against all of these recommendations for automatically granting friendship to test classes...

Personally I prefer to focus on the following to allow me access to the insides of a class that I need to test:

  1. Rely on the public interface of the class where possible; sometimes this means extending the public interface slightly to allow for easier testing. Don't fight these extensions too much but also don't let them drive your design too much...
  2. Consider adding a monitoring interface which can be used by 'real' code as well as test code to enable monitoring of the code under test. (I still surprise myself with how often this is a really good part of the design process).
  3. Consider providing access to some parts of the class to derived classes via a 'protected interface' and derive a 'testable' version of the class in question that can then be instrumented and tested.

In summary, I much prefer to see designed in test points rather than a blanket friendship with a test class. Of course the former is harder to do than the latter but, IMHO, results in better code AND better tests.

Len Holgate
@Len - Good points. I normally try very hard not to have to have public methods just for tests. When it becomes difficult to test some code, then your tests are telling you that your design has problems. You really, really want to have the better design. Spend the time and it will become easier.
quamrana
Listen to your code, smell your code - friendship just for tests stinks!
quamrana