Re: Need help designing some JUnit tests
On 5/20/2010 4:47 PM, Rhino wrote:
Eric Sosman<esosman@ieee-dot-org.invalid> wrote:
[...]
For constructors, what you want to test is that they throw
exceptions when they're supposed to (e.g., InvalidArgumentException),
and that the newly-constructed object satisfies all the invariants
it's supposed to. In your no-argument Foo() constructor exceptions
seem unlikely (possible, though: think HeadlessException), but you
might check `myFoo.getHeight() * myFoo.getWidth() == myFoo.getArea()'
or whatever.
Could you expand on this last paragraph a bit. The part about verifying
that exceptions get thrown at the appropriate time are fine but I'm not
clear on what you mean by the invariants that it is supposed to satisfy.
The last sentence is almost not quite clear. Are you saying to find some
aspect of the work that is done in the constructor and verify that it
took place, so that if it is drawing a GUI component, that the component
exists and has dimensions greater that 0 x 0? What if the constructor
does very very little - maybe just a super() - or even nothing at all? In
those cases, is it sufficient to just do
Read the Javadoc for your Foo class, and consider what
properties a newly-constructed Foo instance should satisfy.
Test that they are satisfied -- that is, test that a newly-
constructed Foo complies with its "contract."
if (Foo == null) fail("Constructor failed to instantiate the class");
Rhino, if you keep on spewing this sort of codecrap I'm going
to shove that horn of yours firmly up the orifice that spews.
You should test that the factory method behaves as advertised.
If it can return null under some circumstances, you should check that
it does so when it's supposed to and does not when it isn't. If it
returns non-null, the thing returned will necessarily be of the type
declared for the factory method -- but not necessarily of that "exact"
type, as it might be a subclass or any arbitrary implementation of an
interface type. That may make a difference in what you test.
Can you elaborate on this a bit? Can you show me a simple example of a
constructor returning a subclass or implementation of an interface?
No, because a constructor cannot do such a thing. But you seemed
to be talking about a factory method (although it's hard to be sure
from reading your codecrap), and a factory method -- any method, in
fact -- can return anything compatible with its declared type. Wasn't
it you who had the problem with SpinnerNumberModel recently, where the
getNumber() method sometimes returned a Short, sometimes a Long,
sometimes something else?
I'd say it's unnecessary to test wait() and notify() and other
final methods of Object. More generally, it's probably unnecessary
to test final methods of any superclass.
But equals() is not final, and if the class being tested has its
own equals() you should test it. (Note that it's extremely rare to
inherit equals() from a superclass unless you're inheriting it all
the way from Object undisturbed.) If you were writing tests for
Integer, you might test `new Integer(42).equals(new Integer("42"))',
for example, and `! new Integer(42).equals(new Integer("-42"))'.
So, in a nutshell, only test the methods of the parent classes if I
overrode them; otherwise, don't worry about them. That makes sense to me!
There's a subtle point there, a conflict between "black box"
and "clear box" testing. The only way you can *know* that a subclass
inherits a non-final method rather than overriding it is to peek
into the subclass' implementation (either by looking at the source
or by using reflection). But what if somebody comes along next week
and decides to override a method you decided not to test, on the
grounds that it was not overridden?
One thing you might do is run some of Super's unit tests on Sub
instances. Another might be to include a "sanity check" test in your
Sub, something that reflects on Sub and verifies that the methods
you've chosen not to test are in fact inherited.
Finally, you've got to realize that unit testing, important as it
is, is not the be-all and end-all of verifying correctness.
--
Eric Sosman
esosman@ieee-dot-org.invalid