views:

176

answers:

3

I have an abstract testcase "AbstractATest" for an interface "A". It has several test methods (@Test) and one abstract method:

protected abstract A unit();

which provides the unit under testing. No i have multiple implementations of "A", e.g. "DefaultA", "ConcurrentA", etc.

My problem: The testcase is huge (~1500 loc) and it's growing. So i wanted to split it into multiple testcases. How can organize/structure this in Junit 4 without the need to have a concrete testcase for every implementation and abstract testcase.

I want e.g. "AInitializeTest", "AExectueTest" and "AStopTest". Each being abstract and containing multiple tests. But for my concrete "ConcurrentA", i only want to have one concrete testcase "ConcurrentATest".

I hope my "problem" is clear.

EDIT
Looks like my description was not that clear.
Is it possible to pass a reference to a test?
I know parameterized tests, but these require static methods, which is not applicable to my setup. Subclasses of an abstract testcase decide about the parameter.

A: 

Why not let each concrete test case initialise a concrete instance for test via a method called via @Before. i.e. you initialise a new instance of the concrete instance prior to each test. The abstract test class can then provide tests working off this instance (referenced via a protected field in the abstract class).

So you'll have one test class per concrete instance, and those will simply provide a new instance to test against. The abstract test class that these derive from provide all the tests. When you create a new concrete type, you simply need a new concrete test class to instantiate an instance of that class.

Brian Agnew
That's you i am doing it with "one" abstract testcase. But how can i break this logic into multiple classes, managed by one abstract testcase.
Willi
A: 

You can introduce a paramter to the test methods and use one @DataProvider creating instances of all classes to be tested. Ok, all in one test.

Arne Burmeister
But my concrete implementations are (of course) spread over several packages/modules/projects which of course do not know of each other.
Willi
Ha, i can get a look - sitting 2,3 km from you ;-)
Arne Burmeister
A: 

I don't know if you've solved this already, but I'd suggest that you keep your one abstract test, but externalize the implementations of the methods in that abstract class.

For example, create a class with your Initialize tests

public class InitializeTester {
    protected static void testInitializeA(A unit) {
        ...
                assertSomething ...
    }

    protected static void testInitializeB(A unit) {
        ...
                assertSomething ...
    }

}

A Class with your Execute Tests:

public class ExecuteTester {
    protected static void testExecuteA(A unit) {
        ...
                assertSomething ...
    }

    protected static void testExecuteB(A unit) {
        ...
                assertSomething ...
    }

}

Then your actual abstract Tester:

public abstract class ATester {
    @Test
    public void testInitializA() {
        InitializeTester.testInitializeA(unit());
    }

    @Test
    public void testInitializB() {
        InitializeTester.testInitializeB(unit());
    }

    @Test
    public void testExecuteA() {
        testExecuteTester.testExecuteA(unit());
    }

    @Test
    public void testExecuteB() {
        testExecuteTester.testExecuteB(unit());
    }

    abstract protected A unit(); 
}

You may end up with the abstract test class having a lot of methods, but they'll all be very short, as they pass control to your Tester classes.

Matthew Flynn
Interesting idea but having to add a method to ATester for every test-method is a lot of boilerplate code and is very likely to be forgotten when adding new test cases.
Willi