March 2005 Archives

Stop! Holub Time

|

Allen Holub is at it again, spouting regressive and toxic notions about OOD. Basically, he's still on his epic kick about "evil accessors," but now he's making the point with a gimp version of XStream that he wrote and some random noise about JSR175 annotations thrown in to get press.

I was thinking about writing more about this but it's late and it just isn't worth the keystrokes. I mean, it's really not that hard: Design contracts with care. Minimize contracts. Separate implementation from contract. Present mulitple contracts (interfaces) where appropriate. Why make it harder than it needs to be?


Fact: Allen Holub's monthly column is the reason I cancelled my free subscription to Java Developer's Journal years ago.

Thread of the Year

|

One Theme, Two great Ads

| | Comments (1)

Man, that first one is still hard to watch.

* Little Boy

* Teenage Mom

I just stumbled across an older blog entry blog entry about JUnit which has helped me better understand the core of the debate over test dependencies. The article presents a justification for JUnit's practice of instantiating a new TestCase instance for every test method it runs. It leads off with an example:

public class Tester extends TestCase {
    public Tester(String name) {super(name);}
    private List list = new ArrayList();
    public void testFirst() {
        list.add("one");
        assertEquals(1, list.size());
    }
    public void testSecond() {
        assertEquals(0, list.size());
    }
}

and provides the following explanation about it:

Some people may not realize this, but both tests pass - and will pass in whichever order they are run. ... One of the key principles in JUnit is that of isolation - that is no test should ever do anything that would cause other tests to fail.

And I do kind of see his point: having all that shared data can definitely lead to fragile code if you aren't careful in the design of your class.

This got me to thinking, though: wouldn't it be great if Java had a way to declare a variable that could only be used *inside* a method? Sounds cool, huh? Maybe I should start a JSR for these things - I think I will call them "Local Variables."

These Local Variables would would be a huge win for JUnit users because they would offer a much simpler way to ensure that test methods operate on fresh data. Let me illustrate how I would see this working in the previous example - try to stay with me:

public class Tester extends TestCase {
    public Tester(String name) {super(name);}
    public void testFirst() {
        List list = new ArrayList();
        list.add("one");
        assertEquals(1, list.size());
    }
    public void testSecond() {
        List list = new ArrayList();
        assertEquals(0, list.size());
    }
}

Isn't that great? Wouldn't it be awesome if we could write tests this way?

</snotty>

Ok, ok, you get the point (I hope). And please don't get me wrong - I like JUnit and have found it very useful, modulo a few annoyances like this.

But the bottom line is that this whole 'test independence' feature that JUnit offers is rooted in a conflation of local and member variables. If you want to have state that is local to a method invocation, Java gives you a perfectly good way to do this.

But Java also gives you a mechanism for associating state with an instance, and there are plenty of valid reasons to want to use it when writing tests. Managing the state of an instance is a fundamental part of OO programming, and competent OO programmers know how to do it without making a mess of things.

By taking away instance variables, JUnit effectively insists that its users are not competent OO programmers. I find this just slightly irksome.

What I find disturbing is that so many JUnit users so vehemently seem to agree.

Cedric's work on TestNG has touched off a series of debates about testing philosophy. The topic du jour is whether it's necessary and acceptable to define one test case that is dependent on another.

I'm really puzzled as to why there is even a debate here (the answer is "yes", BTW). The prevailing groupthink seems to be that since JUnit doesn't let you do it, you shouldn't do it.

I find this a bit frustrating, but Cedric is fully willing to entertain the discussion. I've come to really admire Cedric for his ability to be patient with folks who are a little short on clues. I guess that's how you get to be such serverside a rock star.