Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JUnit Tests: object not recreated between parameterized tests

I'm trying to test implementations of a Collections interface using JUnit4 Parameterized tests. My test class has two tests:

@RunWith(Parameterized.class)
public class CollectionsTest {

    private Collection<String> col;
    private Collection<String> other;

    public CollectionsTest(Collection<String> c, Collection<String> other) {
        this.col = c;
        this.other = other;
    }

    @Parameterized.Parameters
    public static java.util.Collection<Object[]> tokenStreams() {
        return (java.util.Collection<Object[]>) Arrays.asList(new Object[][] { 
            { new DSLinkedList<String>(), new DSLinkedList<String>() } });
    }

    @Test
    public final void isEmpty() {
        assertTrue(col.getClass().getName() + ".isEmpty() should return true when collection contains no elements", col.isEmpty()); 
        col.add("Stringthing");
        assertFalse(col.getClass().getName() + ".isEmpty() should return false when collection contains elements", col.isEmpty());
    }

    @Test
    public final void size() {
        assertEquals(col.getClass().getName() + ".size() should be 0 for an empty collection.", 0, col.size());
        col.add("String");
        assertEquals(col.getClass().getName() + ".size() should be 1 for a collection with one element.", 1, col.size());       
    }
}

The second test (size()) always fails: at the time of the first assertion, col contains a single element stringThing, because I inserted an element in the isEmpty() test.

How do I clean the parameterized objects between tests?

If I wasn't using a parameterized test, I'd use @Before with a setup() method: should I be using reflection and a setup method here to recreate the col and other objects? (I haven't done this because I don't know which Collection implementation each test is running beforehand: if I have to manually write code using reflection to determine this, what's the point of Parameterized tests?)

My understanding is that the Parameterized tests call the constructor before each test, which should 'reset' my objects cleanly: why is this not the case?

like image 883
simont Avatar asked Aug 31 '25 22:08

simont


2 Answers

In Java 8 this can be done fairly cleanly using lambda expressions and the utility class java.util.function.Supplier. Instead of providing an instance of the parameter type, you provide a lambda which supplies a new instance each time it is evaluated. JUnit passes the lambda to the constructor for each test case, where a new instance is created with a call to get().

@RunWith(Parameterized.class)
public class CollectionsTest {

  private Collection<String> col;
  private Collection<String> other;

  public CollectionsTest(Supplier<Collection<String>> c, Supplier<Collection<String>> other) {
    this.col = c.get();
    this.other = other.get();
}

@Parameterized.Parameters
public static java.util.Collection<Object[]> tokenStreams() {
    Supplier<Collection<String>> c1 = () -> new DSLinkedList<String>();
    Supplier<Collection<String>> c2 = () -> new DSLinkedList<String>();

    return Arrays.asList(new Object[][] { { c1, c2 } });
}

@Test
public final void isEmpty() {
    assertTrue(col.getClass().getName() + ".isEmpty() should return true when collection contains no elements", col.isEmpty()); 
    col.add("Stringthing");
    assertFalse(col.getClass().getName() + ".isEmpty() should return false when collection contains elements", col.isEmpty());
}

@Test
public final void size() {
    assertEquals(col.getClass().getName() + ".size() should be 0 for an empty collection.", 0, col.size());
    col.add("String");
    assertEquals(col.getClass().getName() + ".size() should be 1 for a collection with one element.", 1, col.size());       
}
like image 198
James Scriven Avatar answered Sep 03 '25 15:09

James Scriven


Parameterized creates a new CollectionsTest object before each tests and calls the constructor, but it passes the same DSLinkedList objects each time, tokenStreams() is called only once for whole testcase. You should clean the lists in the constructor yourself.

like image 32
Evgeniy Dorofeev Avatar answered Sep 03 '25 13:09

Evgeniy Dorofeev