Re: Need help designing some JUnit tests
Eric Sosman <esosman@ieee-dot-org.invalid> wrote in news:ht44ki$8rm$1
@news.eternal-september.org:
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.
Sorry!! I just dashed that off quickly from memory and I obviously missed
a few bits.... It was really just meant to be illustrate a standard
constructor but perhaps I should have lifted one from an actual class (or
omitted the class code altogether)....
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.
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
if (Foo == null) fail("Constructor failed to instantiate the class");
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.
Sorry!!
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?
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
Again, sorry....
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"))'.
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!
Thanks!!
--
Rhino