I was annoyed to find in the Parameterized documentation that "when running a parameterized test class, instances are created for the cross-product of the test methods and the test data elements." This means that the constructor is run once for every single test, instead of before running all of the tests. I have an expensive operation (1-5 seconds) that I put in the constructor, and now the operation is repeated way too many times, slowing the whole test suite needlessly. The operation is only needed once to set the state for all of the tests. How can I run several tests with one instance of a parameterized test?
1 Answer
I would move the expensive operation to a @BeforeClass method, which should execute just once for the entire parameterized test.
A silly example is shown below:
@RunWith(Parameterized.class)
public class QuickTest {
private static Object expensiveObject;
private final int value;
@BeforeClass
public static void before() {
System.out.println("Before class!");
expensiveObject = new String("Just joking!");
}
@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] { { 1 }, { 2 } });
}
public QuickTest(int value) {
this.value = value;
}
@Test
public void test() {
System.out.println(String.format("Ran test #%d.", value));
System.out.println(expensiveObject);
}
}
Will print:
Before class!
Ran test #1.
Just joking!
Ran test #2.
Just joking!
8 Comments
Nate Glenn
Ah! Thanks. I was using Before and AfterClass as if they would run before and after the first and last parameterized tests. Is there a way to do that (static block for before, and something else for after...)?
Duncan Jones
Not sure I understand what you want.
@BeforeClass and @AfterClass would allow you to set-up and tear-down your test data. Both need to be public static void methods.Nate Glenn
Yes, that's exactly what I asked for in my question. I was just wondering, because I was using BeforeClass and AfterClass incorrectly, if there's a way to run stuff before starting any of the tests and after finishing all of the tests.
Duncan Jones
I'm very confused now! To run stuff before starting any tests, use
@BeforeClass. To run stuff after all the tests, use @AfterClass. There are no other options that I know of! What functionality are you looking for that isn't provided by @BeforeClass and @AfterClass?Nate Glenn
@BeforeClass and @AfterClass are run before and after each parameterized test. So, with 5 parameter elements they would each run 5 times. I'm asking for something that would be run by JUnit before and after running all of the parameterized tests. So even with 5 parameter elements they would only be run once. |