1

So, for example I have a few classes implementing the List<T> interface. How to test them - whether they implement the methods correctly?

Now I only see one way to do so:

public class MyListImplementationsTest {
    private Collection<List<Integer>> listImplementations;

    @BeforeClass
    public static void setUp() throws Exception {
        listImplementations = Arrays.asList(
            new QuickList<Integer>(), new EfficientMemoryList<Integer>()
        );
    }

    @Test
    public void testIsEmptyAfterCreationEmptyList() {
        // Use forEachList(handler) in order to not iterate
        // the lists manually every time.
        // May be there is no need to do so,
        // because using <<for (item : items)>> instead of
        // iterating using index prevents from OutOfBounds errors
        forEachList(new OnEachListHandler<Integer>() {
            @Override
            public void onEach(List<Integer> list) {
                assertTrue(list.isEmpty());
            }
        });
    }

    private <T> void forEachList(OnEachListHandler<T> handler) {
        for (List<T> each : listImplementations) {
            handler.onEach(each);
        }
    }

    private static interface OnEachListHandler<T> {
        void onEach(List<T> each);
    }
}

But in my opinion it's complicated to iterate lists in every test.

Is there more elegant way to test classes implementing the same interface in JUnit4?

3 Answers 3

2

You can create a base test which can test anything of type List<T> plus an abstract method which creates such a list.

Then implement a test per list type which extends the base test. JUnit will run the test cases from the base class plus any that you define in the extension.

abstract class AbstractListTest<T> {
    protected abstract List<T> createList();

    @Test
    public void testIsEmpty() {
        List<T> list = createList();
        assertTrue(list.isEmpty());
    }

    ...more tests...
}

class QuickListTest extends AbstractListTest<QuickList> {
    protected QuickList createList() {
        return new QuickList();
    }
}

JUnit won't run the abstract base class but it will see the inherited tests and run all of them. You can also add new tests to QuickListTest or override ones from the base class.

Basically, JUnit will take the class, find all public @Test methods from the whole inheritance tree and run them.

Sign up to request clarification or add additional context in comments.

2 Comments

But how can JUnit run the tests from the base class if it's abstract ?
Subclass the base class and implement an abstract factory method. JUnit will run the implemented methods on the superclass just fine.
0

I will consider breaking up the tests for different list implementations into their respective test cases, so that they pass or fail independently.

Using your .isEmpty() as an example, if QuickList.isEmpty() and EfficientMemoryList.isEmpty() have different implementations i.e. different meaning for the concept of empty, then it makes sense for them to be tested independently. Currently, your testIsEmptyAfterCreationEmptyList will fail if 1 list implementation failed, but the others passed.

Otherwise, if QuickList.isEmpty() and EfficientMemoryList.isEmpty() share the same implementation, then you can consider moving the implementation to a common base class, and write tests for that base class.

Just because classes share the same interface, doesn't mean their tests need to be lumped and coupled.

Comments

0

Create a test each implementation separatelly: QuickListTest and EfficientMemoryListTest.

QuickListTest.java

public class QuickListTest extends ListBase {   
    @Test
    public void shouldBeEmpty() throws Exception {   
        assertThatIsEmpty(new QuickList<Integer>());   
    }    
}

BaseList.java

public abstract class ListBase {    
    protected void assertThatIsEmpty(QuickList<Integer> actual) {
        assertThat(actual).isEmpty();
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.