Re: Need help designing some JUnit tests
On 05/20/2010 01:48 PM, Rhino wrote:
I'm getting more and more comfortable with JUnit after a long absence
from it but I'm still struggling with composing tests for some
situations. If anyone can help with any of these situations, I'd love to
hear your suggestions.
There may be several "right" answers to your questions. I will take a stab at
some of them.
--------------------------------
Scenario 1 - Moving Targets
What is the best way to test a method whose output is unpredictable
because that output is a moving target? For example, I have a method that
When the target "moves", write new tests.
A unit test should test the behaviors of the methods given the domain of
inputs and range of desired outputs or responses. Thus, given your scenario:
uses Locale.getAvailableLocales() to display all of the Locales on the
current JVM. It works fine but how do I write a JUnit test, given that an
upgrade to the JVM could introduce additional Locales? I'd have the same
Your current JVM doesn't have new Locales, so writing for ones that don't
exist is clearly not possible. However, you can use
<http://java.sun.com/javase/6/docs/api/java/util/Locale.html#getAvailableLocales()>
to return an array of all currently available locales, and for-loop through
them in your unit test:
for ( Locale loc : Locale.getAvailableLocales() )
{
assertTrue( "insane", sanityCheck( loc ));
}
kind of problem if a method was returning a list of area codes or cell
phone providers. There must be some standard way of writing a JUnit test
for that but I'm drawing a blank.
--------------------------------
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");
}
If not, what would be a better test?
No, it's ridiculous. It is literally impossible for 'new Foo()' to return an
instance of something that is not an instance of Foo, so checking for that is
wacky. Checking that the constructor does not throw an exception is what you
want.
--------------------------------
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() {
Where is your return value?
This won't even compile.
return Foo();
}
public getInstance(Locale locale) {
return Foo(locale);
}
Where is your return value?
This won't even compile.
Is it necessary to write JUnit tests for the constructors, given that
they are private?
Write a test for the method, after you get it to compile.
Normally you don't unit-test private or package-private methods, as they are
not part of the published contract. Unit tests usually test the public contract.
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");
}
If 'getInstance()', for which you did not show a return type, has a return
type of 'Fuzz', then testing that the returned value is an instance of that
type is wacky. The compiler guarantees it, so a run-time test is silly. You
want to test what happens at run time, i.e., that the returned value exists,
is not null, and there was no exception.
Actually, it's also valid to test that there is an exception thrown if initial
conditions demand it. For example, testing a constructor that takes an
argument that must not be null, you might pass a null argument and confirm the
'IllegalArgumentException' from the constructor.
It's just plain foolish to test that the type of the result matches what the
compiler already guarantees is the type of the result. Unit tests are for
run-time behaviors.
public void testGetInstancelocale() {
Fuzz fuzz = Fuzz.getInstance(new Locale("FR", "fr"));
if (!fuzz instanceof Fuzz) fail("Failed to instantiate Fuzz"):
}
If not, what tests 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
Depends.
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
Not sure how you'd write a test for 'wait()'. Writing a test for 'equals()'
makes sense IF the class overrides 'equals()', in which case you'd also test
that 'hashCode()' and 'toString()' match, as should 'compareTo()' if the class
implements 'Comparable<YourType>'. It is quite important that those overrides
be consistent.
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
Depends. Did you override them?
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.
The reason is that you routinely override methods like 'equals()' (and
'hashCode()', 'toString()' and 'compareTo()' with it).
--
Lew