Last Updated: February 25, 2016
·
2.776K
· Dave Watts

Don't unit test third-party code

When you're writing unit tests, make sure the tests you're writing exercise as little third-party code as possible.

  • You don't benefit from the test coverage
  • The setup, teardown and assertions clutter your test classes
  • All the successful assertions might make you think you've written a great test when all you've really done is confirm the JDK/lib works as it should.
    • If you don't trust that the third-party code is right, why are you using it?

contrived example time!

Imagine a Map wrapper that adds type safety to a HashMap. You might have the following

import java.util.HashMap;

public class IntegerMap extends HashMap
{
    public Integer put(Object k, Integer v)
    {
        return (Integer) super.put(k, v);
    }

    @Override
    public Integer get(Object key)
    {
        return (Integer) super.get(key);
    }
}

As I said, contrived...

You could quite easily end up with the following unit test

public class TestIntegerMap
{
    ensureMapEmptyAfterCreate()
    ensureMapEmptyAfterClear()
    ensureMapNotEmptyAfterAdd()
    ensureMapEmptyAfterClearAddRemove()
    .....
}

While all of these tests confirm that IntegerMap behaves as you expect, almost all of it is redundant. HashMap already starts empty when you create it, so IntegerMap will too. Subsequent calls to get() with the same argument will return the same value. All those tests look great, and give a lot of green lines on your test reports, but they only test HashMap, and prove nothing about your code.

What does IntegerMap actually do? It simply hands off arguments to HashMap, while restricting the type of some arguments and return values. So what is really worth testing is the interactions with HashMap.

import static org.junit.Assert.assertEquals;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestIntegerMap {
    private static final Object TEST_KEY = new Object();
    private static final Integer TEST_VALUE = new Integer(3);
    private static IntegerMap mapToTest;

    @Before
    public void setUp() throws Exception {
        mapToTest = new IntegerMap();
    }

    @After
    public void tearDown() throws Exception {
        mapToTest = null;
    }

    @Test
    public void testPutGet() {
        mapToTest.put(TEST_KEY, TEST_VALUE);
        Integer returned = mapToTest.get(TEST_KEY);
        assertEquals("Object returned should be the object inserted", TEST_VALUE, returned);
    }
}

That's it. One test covers all your code. No clutter, no wasted effort. Everything else can be assumed to be done by someone else.

If you have third party code of unknown quality, write a test suite before using it. If you need to check you're using a library correctly, write some integration tests to confirm it. Just don't incorporate these tests with the unit tests for your project.