Forgive the title -- it needs work. I am struggling to find better English to express my issue. Edits encouraged.

Example to describe my issue:

Checker Method

I have an argument checking method called public static void StringArgs.checkIndexAndCount(String, int, int). Given a string, an index, and a count, confirm the string is not null, and the index & counts are reasonable. Unchecked (runtime) exceptions are used to report errors. There is a battery of unit tests written to check all angles of this method.

Layered (or Derived) Method

The checker method is called by other methods, such as public static String removeByIndexAndCount(String, int, int). The first line of this method checks the arguments by calling the above checker.

Unit Test Strategy

When I write unit tests for the second/layered/derived method, how do I account for the existing set of unit tests for the checker method? It seems to violate duplication/copy-paste principles to simple re-add the same unit tests (modified slightly) from the checker method to the second method.

Please advise.

My code is Java, but I don't think that particularly relevant, as this same issue could occur in any language.

2 Answers
2

There is no need to test all the scenario's for the Checker method when testing X. All you really need to do in testing X is to ensure that it actually does use the Checker method, so you can indeed forego all those test input scenario's to X.

The way to do that is the same way I would ensure that Asserts I have coded that are essential to validating the contract for a method, are still in place: code a single test that should trigger the assert and check that the EAssertionFailed (or whatever) exception is indeed raised.

For your scenario that would mean coding a single test for method X to ensure that it actually calls the 'Checker' method. For example by using test input for which Checker would would raise an exception.

Of course some clever programmer could thwart this check by checking for this input in X and returning the same exception. But you have to draw the line somewhere. You are not protecting against hackers but against someone forgetting to use Checker and/or inadvertent removal of the call to Checker.

Can you provide a simple, concrete example in code?
–
kevinarpeJul 27 '13 at 19:22

@kevinarpe: Really? I mean, the methods even have the same signature and you have a battery of test on the Checker function that throws exceptions. I am sure that you can use the same code to check that the expected Checker exception does indeed get thrown when providing invalid input to your "Layered or Derived Method".
–
Marjan VenemaJul 28 '13 at 8:24

In general, I wouldn't focus too much on reducing repetition in unit tests. You need to test the lower-level module so it can be reliably re-used, and you need to test the higher-level one in case you change it to stop using the lower-level module. Writing these tests is a little laborious, but once they're written the repetition will not cause the same kind of code quality issues as repeated production code in my experience.