Basic JUnit questions

E

Eric Sosman

How often do you propose to do this inspection, and how you propose to
ensure that it is done?

I suggest re-inspection any time either of the methods
changes, or if there's a substantive change to any of the
fields that affect them (making a non-final field non-private,
for example).

How to ensure that it's done? The same way (I suppose)
you would ensure that a unit test was carefully written, not
just checking "x".equals("x") and declaring victory. I'd do
the work myself, or I'd tell others to do it, and I'd trust
them to act like responsible grown-ups. If they didn't, I'd
get angry -- and although I'm generally an easy-going sort of
guy, "you wouldn't like me when I'm angry."

The procedures and disciplines that get code reviews done
can get other things done, too.
 
R

Rhino

Thank you all VERY much for your confirmation that I was on the right
track!

And sorry about losing that extra parameter in my example. I lost my train
of thought in there somewhere ;-)
 
A

Arne Vajhøj

On 3/18/2010 3:22 PM, Rhino wrote:
I think I understand the basics of using JUnit - I'm still using JUnit3
for the moment - but I want to ask some things that I don't find
clear in
the documentation that I've found.

Would it be reasonable to say all of the following?

1. For each class that I develop, I should have one JUnit class that
extends TestCase and that this TestCase class should test each of the
methods in the class I developed?
[...]
"Each method" may be a overkill, too. Getters and setters come
to mind as "too simple to test" -- usually.

I recommend testing them as well.

They are easy to test and weird things have been seen in code before.

Well, I *did* say "usually."

If setters are supposed to do something more than merely
set a value -- fire change events, say, or recompute allied
values other than the ones directly set -- that's worth testing.
If getters return arrays, it's worth verifying that mucking with
the returned array doesn't magically modify the state of the
object it came from (unless it's supposed to, in which case one
should test that it actually does). And so on, and so on.

But I put it to you that

public void setScrew(int screw) {
this.screw = screw;
}

... is more amenable to verification by inspection than by test.

People can mess up one line as well.

Before IDE's generated setters the following sometimes happen
during copy paste from setNail.

public void setScrew(int nail) {
this.nail = nail;
}

I would not drop unit tests for inspection. Nor drop inspection
for unit tests.
As to ease of testing, I note that the code to test a simple
getter or setter is more complex than the code tested; something
seems fundamentally wrong with this. If we think a one-liner
needs testing, why aren't we writing tests for the umpteen-line
test class?

The benefits of unit testing unit tests would probably be
very minimal.

Arne
 
A

Arne Vajhøj

I use different criteria. The Eclipse "Source" code generation seems to
be well tested. If I merely told Eclipse to generate a setter or getter,
or the equals/hashCode pair, I don't write a test. If I wrote a getter
or setter myself, it needs testing. I'm fully capable of making a
mistake in a single line of code.

Code generation has almost removed the chance of errors in
simple getters and setters.

But I would hesitate to make decisions about unit test strategy
based on assumptions that the programmer writing the original
code did (or will if the tests are written first) use the tools
as intended.

Arne
 
A

Arne Vajhøj

However, you often test getters and setters in the course of testing
other methods. For example:

@Test
testOverdraftLimit() {
Account ac = new Account();
ac.setBalance(100000);
ac.setOverdraftLimit(20000);
int withdrawn = ac.withdraw(150000);
assertEqual(120000, withdrawn);
assertEqual(-20000, ac.getBalance());
}

That method is ostensibly about testing the overdraft limit logic, but
it depends on setBalance and getBalance working right. If they don't, it
will break, and you'll find out about it.

True.

And if it is all done by the same person, then "the difference
is equal".

But if the programmer writing OverDraftLimit received an
Account class from somebody else and were told that it was
unit tested, then I believe that there is basis for a
complaint.

Arne
 
J

Jean-Baptiste Nizet

Rhino a écrit :
Now THAT is helpful! In fact, it means that I can consolidate all of the
testing for a given method into a single method in the TestCase class
rather than having a substantial number of tiny test methods for a given
method in the class I developed. And that's where I was hoping to end up
when I asked the question in the first place.

You have to find a good compromise. Smaller test methods are easier to
write, read and understand, and they spot a specific bug. If you have
very long test methods, the first failed assertion will stop the test
method, and all the other, unrelated assertions, won't be tested.

For example, let's suppose I have this kind of method :
public void divide(int dividend, int divisor) {
if (divisor == 0) {
throw new IllegalArgumentException("divisor may not be 0");
}
return dividend / divisor;
}

I prefer to have a test for the nominal case, and another one for the
exceptional case :

public void testDivide() {
assertEquals(3, myObject.divide(6, 2));
}

public void testDivideWhenBadArgument() {
try {
myObject.divide(6, 0);
fail("divide should have thrown an IllegalArgumentException");
}
catch (IllegalArgumentException e) {
// expected
}
}

This may seem overkill, but once your tested method gets longer, more
complicated, and with more code branches, having multiple smaller test
cases is often easier and more maintainable.

JB.
 
M

Mike Schilling

Eric said:
This is true: Sometimes "maintenance" and "enhancement"
are synonyms for "bit rot."

But I'm curious: What sort of a test do you write to ensure
that equals() and hashCode() play nicely together? For example,
if you were writing unit tests for java.lang.String, what would
they look like?

Not compiled or tested, so typos are inevitable:

// Strings that are interesting and varied, and include all the edge
cases I
// can think of. All are distinct.
String[] strings = .new String[] {...};

for (int i = 0; i < strings.length; i++)
{
for (int j = 0; j < strings.length; j++)
{
if (i == j)
{
String s = strings;
String t = new String(s);
assertEquals("'" + s + "' != '" + t + "'", s, t);
assertEquals("'" + s + "'.hashCode() != '" + s +
"'.hashCode()", s.hashCode(), t.hashCode());
}
else
{
String s = strings;
String t = strings[j];
assertNotEquals("'" + s + "' == '" + t + "'", s, t);
}
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,967
Messages
2,570,148
Members
46,694
Latest member
LetaCadwal

Latest Threads

Top