2

I am trying to write contract tests for some widely used interfaces:

Along the lines of:

public abstract class MyInterfaceContractTest extends TestCase {

  private MyInterface _toTest;

  public void setUp(){
    _toTest = getTestableImplementation();
  }

  protected abstract MyInterface getTestableImplementation();

  public void testContract(){

  }
}

...and...

public class MyInterfaceImplementationTest extends MyInterfaceContractTest {

  protected MyInterface getTestableImplementation(){
    return new MyInterfaceImplementation(...);
  }
}

However, I want to be able to test multiple instances of MyInterfaceImplementation. In my use case, this is an immutable object containing a collection of data (with accessors specified as per the interface MyInterface), and it might be empty, or have a small amount of data, or even lots of data.

So the question is, how can I test multiple instances of my implementations?

At the moment, I have to initialise the implementation to pass it into the abstract contract test. One approach would be to have multiple test classes for each implementation, where each test class tests a particular instance of that implementation - but that then seems a bit voluminous and difficult to keep track of.

FWIW, I'm using JUnit 3.

amaidment
  • 6,942
  • 5
  • 52
  • 88
  • JUnit 3 is ancient. Why not use JUnit 4? – Don Roby Jun 22 '12 at 13:41
  • @DonRoby - would that make a difference to solving my problem? I'm using JUnit 3 because that's what our unit tests are currently written in, and it's never been a priority to upgrade to JUnit 4. – amaidment Jun 22 '12 at 13:58
  • http://junit.sourceforge.net/javadoc/org/junit/runners/Parameterized.html might be useful. – Don Roby Jun 22 '12 at 14:07
  • If I understand you correctly, you may use a factory to create your test implementation instances on request. There's a few other ways to approach this I reckon. – maksimov Jun 22 '12 at 14:07

2 Answers2

3

Generally the approach would be to use a "testable" subclass of the abstract class to test all the functionality of the abstract class in one test. Then write a separate test for each concrete implementation testing just the methods defined / implemented in the concrete class (don't retest the functionality in the concrete class).

John B
  • 32,493
  • 6
  • 77
  • 98
  • +1: This is definitely a good tactic for an abstract class with some of the functionality defined there. For multiple implementations of a plain interface, you're likely better off with a parametrized test. – Don Roby Jul 03 '12 at 15:16
  • I do this for testing implementations with no extra methods too. The failure messages are better than with parameterized tests, and it's easier to selectively run the tests for a single implementation. – Tom Anderson Jul 06 '12 at 08:15
2

If I've understood your need correctly, you want to run the same test method or methods with multiple implementations of the same interface.

I don't know how to do this very nicely in JUnit 3.

If you're willing to upgrade to JUnit 4, this can be done by using a parametrized test.

For the simple example of running a single test method on two implementations of an interface, your test code could look something like this:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import java.util.Arrays;
import java.util.Collection;

import static junit.framework.Assert.assertEquals;

// Tell JUnit4 to run it as a parametrized test.
@RunWith(Parameterized.class)
public class MyInterfaceContractTest {

    private MyInterface _toTest;

    // Load the test data into your test instance via constructor
    public MyInterfaceContractTest(MyInterface impl) {
        this._toTest = impl;
    }

    // Supply the test data, in this example just the two implementations you want to test.
    @Parameterized.Parameters
    public static Collection<Object[]> generateData() {
        return Arrays.asList(new Object[]{new MyInterfaceImpl1()}, new Object[]{new MyInterfaceImpl2()});
    }

    @Test
    public void testContract(){
        // assert whatever, using your _toTest field
    }
}

On running this test, JUnit will run the test twice, calling the constructor with the successive entries in the parameter list.

If you have more complex things, like different expectations for the different implementations, the data generation could return lists of Object arrays that contain multiple elements, and the constructor would then take a corresponding multiple arguments.

If you need to reinitialize the object under test between test methods, you might also want to use the trick I described in this related question.

I believe similar things are possible in TestNG, which might be another choice for your upgrade path.

Community
  • 1
  • 1
Don Roby
  • 40,677
  • 6
  • 91
  • 113