Re: Need help designing some JUnit tests
On 5/20/2010 1:48 PM, Rhino wrote:
[...]
Scenario 2 - Constructors
Given a hypothetical class named Foo where the constructor is:
public Foo () {
//anything from no code at all to umpteen lines
}
is this adequate as a JUnit test?
public void testFoo() {
Foo myFoo = new Foo();
if (!myFoo instanceof Foo) fail ("Failed to instantiate Foo");
}
This is inadequate because it won't compile. Insert the
missing parentheses and it's not inadequate, but it's pointless:
if the `new' completes without throwing an exception, `myFoo'
*will* be an instance of Foo -- in fact, it will be an instance
of Foo exactly, and not even of a Foo subclass.
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.
Scenario 3 - getInstance()
Given a hypothetical class named Fuzz where the constructors and
getInstance() methods are:
private Fuzz() {
// do something
}
private Fuzz(Locale locale) {
// do something
// initialize instance variable for locale
}
public getInstance() {
return Foo();
}
public getInstance(Locale locale) {
return Foo(locale);
}
Is it necessary to write JUnit tests for the constructors, given that
they are private?
No, for two reasons. First, since the constructors are private
you can't call them anyhow. Second, the code won't compile.
Would the following be adequate as JUnit tests for the getInstance()
methods?
public void testGetInstance() {
Fuzz fuzz = Fuzz.getInstance();
if (!fuzz instanceof Fuzz) fail("Failed to instantiate Fuzz");
}
Inadequate because (and this is becoming tiresome; I *wish*
people would stop posting garbage and pretending it's code samples!)
the code won't compile.
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.
public void testGetInstancelocale() {
Fuzz fuzz = Fuzz.getInstance(new Locale("FR", "fr"));
if (!fuzz instanceof Fuzz) fail("Failed to instantiate Fuzz"):
}
(Broken) won't (record) compile (broken) won't (record) compile ...
If not, what tests would be better?
Something that compiles would be better. "Hello, world!" for
example, would be better -- not much of a test, I'll grant, but it
would be better.
Lastly - and thanks for bearing with me this far - is it normal practice
to write JUnit tests for all methods that are in parent classes of the
class being tested? For example, while writing tests for one of my
classes, the wizard in Eclipse asked if I wanted to produce test methods
to test methods of Object like equals() and wait(). Should I be writing
tests for those methods as well as for those in my own class? I'm
inclined to assume that the methods in Object, for example, have already
been thoroughly tested and further testing by me seems redundant. Even
parent classes that I myself wrote would presumably have had their own
sets of JUnit Tests. Then again, the Eclipse developers presumably put
that functionality in there for a reason so I'm left unclear about
whether I should be trying to write tests for them too.
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"))'.
--
Eric Sosman
esosman@ieee-dot-org.invalid