Junit4: @Parameters method is executed before @ClassRule initialization. Could it be the way around?

Created on 2 May 2013  ·  9Comments  ·  Source: junit-team/junit4

I have the following problem (using _junit 4.11_):

    @ClassRule
    public static TemporaryFolder tmp = new TemporaryFolder();
    ...
    @Parameters
    public static Collection<Object[]> data() throws Exception {
        return java.util.Arrays.asList(new Object[][] {
            {0, tmp.getRoot().getPath()}
        });
    }

This results in initializationError

java.lang.IllegalStateException: the temporary folder has not yet been created
    at org.junit.rules.TemporaryFolder.getRoot(TemporaryFolder.java:127)

So seems the _@Parameters_ method is executed before the _ClassRule_ initialization phase which makes scenarios like above one a bit complicated.

Most helpful comment

Current workaround:

    protected static TemporaryFolder initStaticTemp() {
        try {
            return new TemporaryFolder() { { before(); } };
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }

    public static TemporaryFolder tmp = initStaticTemp();

    @AfterClass
    public static cleanup() throws Exception {
        tmp.delete();
    }

It works but it needs that manual cleanup...

All 9 comments

Current workaround:

    protected static TemporaryFolder initStaticTemp() {
        try {
            return new TemporaryFolder() { { before(); } };
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }

    public static TemporaryFolder tmp = initStaticTemp();

    @AfterClass
    public static cleanup() throws Exception {
        tmp.delete();
    }

It works but it needs that manual cleanup...

+1

Thinking about it a bit I guess a good way to implement this would be to introduce an annotation for this:

@Parameters
@AfterClassRules
public Object[][] generateParameters() {
    // do stuff
}

This would ensure that both variants are still usable, and that existing code is not broken. If this design is acceptable to the maintainers I would start working on a pull request for this.

I am writing an additional comment because I am not sure if an update on a comment triggers a notification.

Would the design proposed in my previous comment be acceptable to the maintainers? If so, I would start work on a pull-request.

There's a pretty hard architectural problem here: JUnit promises runners like Eclipse that it can enumerate how many tests there are before any of the tests are run, but also wants to minimize any resources consumed during this planning phase. So we really do want to know how many parameters there are going to be before we, for example, create any temporary folders, or do the even more drastic stuff that shows up in ClassRules, like starting servers.

Perhaps my favorite answer would be to enable something like @DataPoints in Theories: there can be static fields or static methods prefixed with @ParameterSet, which are joined together to make the full parameter set. So your example would be:

@ClassRule public static TemporaryFolder tmp = new TemporaryFolder();
@ParameterSet public static Object[] first = new Object[] { 0 };
@ParameterSet public static Object[] second() {
return new Object[] { tmp.getRoot().getPath(); }
}

The point here is that we could count the method "second" without actually executing it.

What do you think?

Hm, I guess now that I think about it, the problem is actually more a smell in my test code. I am connecting to a remote service and running tests depending on how it is configured. Instead I should probably just fix the expected configuration in my test.

Here is the test where I originally faced the issue: CryptoAppExecReturnCodeTest.java

@dsaff I'll give some thought on your suggestion. Initial impression is: splitting pairs into separate arrays needs special care of elements' positions (a bit error prone). So I may end up filling up _first_ with some dummy stuff (just maintaining the number of elements); and in _second_ - I would like to keep the pair elements next to each other:

{ 0, tmp...getPath() },
{ 1, ... }

Is there anything else which runners need besides the number of tests? (E.g. - maybe test names?)

@javornikolov, I just realized that I misread your initial post, and so my response was likely confusing. I was reading your test as two different instantiations of a test class that is constructed with one parameter; now that I read it again, it's actually one instantiation of a test class that is constructed with two parameters. To adjust my proposal then, the suggested code would be:

@ClassRule public static TemporaryFolder tmp = new TemporaryFolder();
@ParameterSet public static Object[] only() {
return new Object[] { 0, tmp.getRoot().getPath(); }
}

I hope that makes my intent clearer; sorry for my initial confusion.

(going through some old bugs)

Perhaps we should rename this issue "Enable something like @DataPoints in Theories"?

(going through some old bugs)

Perhaps we should rename this issue "Enable something like @DataPoints in Theories"?

I would say the issue is to have ability to use Rule resources in the list of parameters for parametrized tests. The approach with @ParameterSet proposed by @dsaff seems viable to me (assuming evaluations happen in such a sequence that original issue is resolved).
But if "Something like @DataPoints" is clear enough and no risk to diverge in some direction not covering original scenario: OK for me.
The reason I prefer Parametrized tests over Theories (which use DataPoints) is that the results of the latter are not reported independently for each set of params, and that first failure aborts the execution of the subsequent params.

Was this page helpful?
0 / 5 - 0 ratings