Categories
Uncategorized

Dynamic JUnit

Recently, I wanted to do something slightly unusual with JUnit. I’m working on a cocoon project, so there are squillions of little XML files floating around. These need to be all well-formed. So I want a test that parses each one. Then, CruiseControl can let us know when they get broken.

First, I gave the task to a colleague. He came up with something that checked each file, and returned a list of the bad ones. It then asserted that the nonWellFormed list had a zero length. Which is great and all, but didn’t tell you which file was broken, nor why.

What I really wanted to do was have a single test per file, so it could display the errors correctly. This seemed like an easy thing to do… Until I tried it. This is what I eventually arrived at:

  class WellFormedTest extends TestCase {
    public static Test suite() {
        final TestSuite suite = new TestSuite(WellFormedTest.class.getCanonicalName());
        // Stupid bloody Java regexes have to match from the beginning of the
        // string.
        Pattern p = Pattern.compile(".*\.(xml|xslt|xconf|xmap)$");
        FindFiles ff = new FindFiles(p) {
            protected void processFile(final File file) {
                suite.addTest(new WellFormedTest(file));
            }
        };
        ff.search("web");
        return suite;
    }

    private File file;

    public WellFormedTest(File file) {
      super("Well-Formed? " + file.toString());
      this.file = file;
    }

    protected void runTest() throws Throwable {
      XmlValidator validator = new XmlValidator();
      String result = validator.isWellFormed(file);
      assertEquals(file.toString(), null, result);
    }
  }
  • FindFiles is a utility class to walk a directory tree. Tell me again why Java doesn’t have something this basic in it’s vast class libraries?
  • You have to call super("blah") in your constructor to name each test sensibly.
  • But if you do this, you have to override runTest() in order for things to actually work. The usual mechanism for determining which tests to run doesn’t work if you supply a custom name. This took forever to work out and required delving into the JUnit source. Halleluljah for Open Source.
    • As part of prodding around in the debugger, I noticed that JUnit creates a new TestCase object for each test in the class. So it’s OK to just do one thing in runTest(), as that’s all that’s going to happen anyway.
  • XmlValidator is another custom helper class. It just parses the file and returns a String containing the error (or null).
  • Yes, this is JUnit 3.8. I know I need to migrate to JUnit 4. That’s a battle for another day, dependent on upgrading ant first.

Originally, I tried to get the test done inside a nested anonymous subclass of TestCase, but there’s no constructor there, so that doesn’t work too well. Plus it bumps the ugliness of the source another level.

The end result works quite well and provides a useful example for doing dynamic tests with JUnit.

Categories
Uncategorized

Java Verbosity

I’ve been doing quite a bit of Java over the last fortnight. It’s much easier with eclipse of course, but it’s still pretty verbose. But I dunno, maybe it’s just me, a whingy old Perl coder. But then again, look what I’ve just found in the Java Cookbook:

  public class Ls {
    public static void main(String argh_my_aching_fingers[]) {
      // ...
    }
  }

Glad to know I’m not the only one. :-)

Categories
Uncategorized

JUnit 4, the downfall

Sadly, after my excitement about Junit 4, I’ve found the downfall: it doesn’t work with ant yet.

However, there does appear to be a workaround. Add this to each class:

  public static junit.framework.Test suite() {
    return new junit.framework.JUnit4TestAdapter(SimpleTest.class);
  }

However, that’s now causing my tests to fail with NullPointerExceptions inside HttpUnit. Yet they work fine in Eclipse. Wonder what I’m doing wrong?

Update: It’s entirely my own fault—my ant task was forgetting to copy over non-java artifacts into the classpath. So adding suite() makes things work just fine.

Categories
Uncategorized

Junit 4

I’ve got a little project at work that’s completely new (hurrah!), and using Java 5. So, I thought I’d give the latest Junit a try. Junit 4 is quite a departure from the older versions. It relies on features only present in Java 5, like annotations. But this does free up the tests from having to inherit from TestCase.

This is the simplest test case.

  import org.junit.Assert;
  import org.junit.Before;
  import org.junit.Test;

  public class MyTest {
    @Before
    public void setUp() throws Exception {
      // ...
    }

    @Test
    public void alwaysTrue() {
      Assert.assertTrue(true);
    }
  }

You can make this slightly nicer by using static imports for the assertions. I didn’t because I wanted eclipse to complete them and I couldn’t auto-discover them as easily. I’ll probably switch shortly.

The annotations are also used for stating which exceptions you wish to catch.

All in all, I’m quite impressed. It’s about as simple as it gets in Java.

Categories
Uncategorized

Ant & JUnit

I’ve just been tripped up by ant & JUnit. I’m appalled. All the proposed solutions are both hackish and ugly. I don’t actually care about the intricacies of ClassLoaders. I just want a simple way to tell ant “junit is over here” so that my build and tests will work on whatever system I check out on. I don’t want to have to install stuff into the ant directory on each system. I already have junit.jar in my codebase, and it should be able to use it.

I suppose I could get around it by writing a build.sh which sets the CLASSPATH correctly, but I thought ant was supposed to avoid all that?