Assume i have a private routine that performs some calculation:
private function TCar.Speed: float
{
Result = m_furlogs * 23;
}
But now i want to begin testing this calculation more thoroughly, so i refactor it out to a separate function:
public function TCar.Speed: float
{
Result = CalculateSpeed(m_furlogs);
}
private function TCar.CalculateSpeed(single furlogs): float
{
Result = furlogs * 23;
}
Now i can perform all kinds of tests on CalculateSpeed
:
Check( CalculateSpeed(0) = 0);
Check( CalculateSpeed(1) = 23);
Check( CalculateSpeed(2) = 46);
Check( CalculateSpeed(88) = -1);
Except that i can't perform these tests, because CalculateSpeed
is private to TCar
. An abstract tennant of unit-testing is that you never test private code - only public interfaces. As a practical matter, *x*Unit is not normally structured to be able to access private methods of the separate class being tested.
The issue is that none of the rest of the class is setup to handle unit-tests. This is the very first routine that will have testing of any kind. And it is very difficult to configure the host class a set of initial conditions that will allow me to test calling CalculateSpeed
with every set of inputs that i would like.
The only alternative i can see, is moving this private calculation out into it's own TCarCalculateSpeed
class:
public class TCarCalculateSpeed
{
public function CalculateSpeed(float furlogs)
{
Result = furlogs * 23;
}
}
A whole class, dedicated to exposing one method, that's supposed to be private, just so i can test it?
Class explosion.
Plus it's private. If i wanted it to be public, i'd rather promote it to public visibility - at least that way i save a separate class being created.
i'd like to add some unit-testing; but it can only be done in small pieces, as code changes. i can't completely redesign functioning 12 year old software, possibly breaking everything, because i wanted to test one internal calculation.
My current, best, thinking is to add a Test
method to my Car
class, and just call that:
TCar Car = new TCar();
Car.RunTests;
public procedure TCar.RunTests
{
Check( CalculateSpeed(0) = 0);
Check( CalculateSpeed(1) = 23);
Check( CalculateSpeed(2) = 46);
Check( CalculateSpeed(88) = -1);
}
But now i have to figure out how to have TCar.RunTests
get trigged by the external TestRunner
, which is only designed to use TestCase
classes.
Note: i've tried my damnest to mix syntax from a bunch of languages. In other words: language agnostic.