Hi all. I believe in programming there is a common consensus to avoid
code duplication, I suppose such terms like 'DRY' are meant to back this
idea. Anyways, I'm working on a little project and I'm using TDD (still
trying to get a hang of the process) and am trying to test the
functionality within a method. Whoever it so happens to verify the
output from the method I have to employ the same algorithm within the
method to do the verification since there is no way I can determine the
output before hand.
So in this scenario is it OK to duplicate the algorithm to be tested
within the test codes or refactor the method such that it can be used
within test codes to verify itself(??).
Neither -- that's essentially a pointless test. The only way to
*correctly* test a function is to compare the result of that function to
an *independent* test. If you test a function against itself, of course
it will always pass:
def plus_one(x):
"""Return x plus 1."""
return x-1 # Oops, a bug.
# Test it is correct:
assert plus_one(5) == plus_one(5)
The only general advice I can give is:
(1) Think very hard about finding an alternative algorithm to calculate
the same result. There usually will be one.
(2) If there's not, at least come up with an alternative implementation.
It doesn't need to be particularly efficient, because it will only be
called for testing. A rather silly example:
def plus_one_testing(x):
"""Return x plus 1 using a different algorithm for testing."""
if type(x) in (int, long):
temp = 1
for i in range(x-1):
temp += 1
return temp
else:
floating_part = x - int(x)
return floating_part + plus_one_testing(int(x))
(The only problem is, if a test fails, you may not be sure whether it's
because your test function is wrong or your production function.)
(3) Often you can check a few results by hand. Even if it takes you
fifteen minutes, at least that gives you one good test. If need be, get a
colleague to check your results.
(4) Test failure modes. It might be really hard to calculate func(arg)
independently for all possible arguments, but if you know that func(obj)
should fail, at least you can test that. E.g. it's hard to test whether
or not you've downloaded the contents of a URL correctly without actually
downloading it, but you know that
http://example.com/ should fail because
that domain doesn't exist.
(5) Test the consequences of your function rather than the exact results.
E.g. if it's too difficult to calculate plus_one(x) independently:
assert plus_one(x) > x # except for x = inf or -inf
assert plus_one( -plus_one(x) ) == x # -(x+1)+1 = x
(6) While complete test coverage is the ideal you aspire to, any tests
are better than no tests. But they have to be good tests to be useful.
Even *one* test is better than no tests.
Hope this helps.