[Biojava-l] Unit tests

Keith James kdj@sanger.ac.uk
14 May 2001 14:59:23 +0100


>>>>> "Matthew" == Matthew Pocock <mrp@sanger.ac.uk> writes:

    Matthew> Testing would have caught several of our recurent
    Matthew> bugs. Long over-due.  Parallel source trees get my
    Matthew> vote. Munging test cases under the src/ tree is an
    Matthew> over-my-dead-body option (but then you can always depose
    Matthew> me). JUnit is fine by me and seems to be the defacto
    Matthew> standard. We can let the classloader do the tree merging
    Matthew> magic necisary to test private API, but as Thomas said,
    Matthew> most of the time you will be wanting to validate that
    Matthew> implementations conform to interfaces. Does JUnit allow
    Matthew> you to define tests for an interface and then apply that
    Matthew> to a collection of objects that implement it? That would
    Matthew> be ideal for us.

As far as I can see, there isn't a built-in system within JUnit for
testing interfaces. I think we would need to write a test fixture to
do this - is there a neat way to get from a Class object for an
interface a list of everything which implements it?

Anyway, I've set up a trial system on my local copy of the source
which seems to work fine:

source is in src/org/biojava/*
tests are in test/org/biojava/*

The copy and compile tasks take both trees and compile them in
ant-build/src so that the source and tests stay in sync.

A 'runtests' target is added which will run if JUnit is in your
CLASSPATH:

<property name="env.classpath" value="${java.class.path}" />

<available classpath="${env.classpath}"
           classname="junit.framework.TestCase"
           property="junit.present" />

  <!-- Run tests -->
  <target name="runtests" depends="init,compile" if="junit.present">
    <junit printsummary="yes" haltonfailure="no" dir="${build.dest}">
      <formatter type="plain" usefile="true" />
      <classpath>
        <pathelement path="${classpath}" />
        <pathelement path="${env.classpath}" />
        <pathelement path="${build.dest}" />
      </classpath>
      <batchtest fork="yes" todir="${reports.tests.dir}">
        <fileset dir="${build.dest}">
          <include name="**/*JUTest*" />
        </fileset>
      </batchtest>
    </junit>
  </target>

Tests are run in a forked VM to avoid accidental exiting from the VM
Ant is running in. At the moment tests are located by Ant scanning the
ant-build/classes directory with the pattern "**/*JUTest*" because
there are a few non-JUnit tests in the main source tree which get
picked up using "**/*Test*" or "**/*Test.class".

The Ant test runner looks for a static suite() method in matching
classes and runs any resulting Test returned by it. If none is present
it makes a TestSuite (which implements Test) and adds all methods
starting with the string 'test' to it, then runs that.

Any new test classes will be picked up automatically by Ant, provided
their names contain 'JUTest' (naming convention negiotiable). These
are omitted from the jar packaging using the same pattern.

Requires Ant 1.3 and JUnit > 3.2 (I used JUnit 3.6). JUnit should be
on the CLASSPATH, otherwise the tests will be skipped. It doesn't add
any external dependencies.

Example test (in this case not defining it own TestSuite):

package org.biojava.bio.symbol;

import junit.framework.TestCase;

public class RangeLocationJUTest extends TestCase
{
   protected Location r1;

   public RangeLocationJUTest(String name)
   {
      super(name);
   }

   protected void setUp()
   {
      r1 = new RangeLocation(1, 100);
   }

   public void testEquals()
   {
      assertEquals(r1, r1);
      assertEquals(r1, new RangeLocation(1, 100);
   }
}


If this seems sensible, let me know and I'll apply the changes. If
not, give an idea of what needs fixing.

cheers,

-- 

-= Keith James - kdj@sanger.ac.uk - http://www.sanger.ac.uk/Users/kdj =-
The Sanger Centre, Wellcome Trust Genome Campus, Hinxton, Cambs CB10 1SA