JUnit @Rule生命周期与@Before的交互

12

我有一些使用 TemporaryFolder @Rule的JUnit测试。它们在 @Before 方法中使用 TemporaryFolder 执行一些设置:

@Rule
public TemporaryFolder folder = new TemporaryFolder();

@Before
public void init() {
  folder.newFile("my-file.txt");
}

@Test
public void myTest() { ... }
大多数情况下,这个方法是完美的。但是,当使用SpringJUnit4ClassRunner时,我发现在某些情况下,在我的TemporaryFolder实例中的Statement被应用之前会调用init()方法。因此,在使用init()时,临时文件夹位置未设置(即null),我的文件最终位于工作目录而不是/tmp
所以,在某些情况下,@Before方法比规则先执行,然而我无法确定一个明确的模式。我有时也会看到我的一些规则实施类似的问题。
是否有任何方法可以确保我的规则语句在任何设置方法之前应用?
2个回答

12
在JUnit 4.10中,BlockJUnit4ClassRunner(SpringJUnit4ClassRunner的超类)似乎会以这样的方式构建Statement链,即规则会在任何@Before方法之前运行。根据JUnit 4.10的文档:
protected Statement methodBlock(FrameworkMethod method) {
    // ...
    Statement statement= methodInvoker(method, test);
    statement= possiblyExpectingExceptions(method, test, statement);
    statement= withPotentialTimeout(method, test, statement);
    statement= withBefores(method, test, statement);
    statement= withAfters(method, test, statement);
    statement= withRules(method, test, statement);
    return statement;
}

JUnit 4.7似乎以不同的顺序将Statement链拼接在一起:

Statement statement= methodInvoker(method, test);
statement= possiblyExpectingExceptions(method, test, statement);
statement= withPotentialTimeout(method, test, statement);
statement= withRules(method, test, statement);
statement= withBefores(method, test, statement);
statement= withAfters(method, test, statement);
return statement;

spring-test-3.0.5的父POM似乎表明它依赖于JUnit 4.7。我想知道是否使用更新的JUnit会有帮助?


1
很好的发现@pholser。我正在使用JUnit 4.8.x,它似乎按照4.10相同的顺序构建链。然而,在SpringJUnit4ClassRunner中覆盖了methodBlock()方法,并设置了一个类似于JUnit 4.7的不同顺序。 - teabot

0

就我个人而言,我使用以下方法作为快速解决方案:

@Rule
public TemporaryFolder tmpFolder = new TemporaryFolder() {
    @Override
    protected void before() throws Throwable {
        if (getRoot() == null) {
            super.before();
        }
    }

    @Override
    public File newFile(String fileName) throws IOException {
        try {
            before();
        }
        catch (Throwable t) {
            throw new RuntimeException(t.getMessage(), t);
        }

        return super.newFile(fileName);
    }

    @Override
    public File newFolder(String folderName) {
        try {
            before();
        }
        catch (Throwable t) {
            throw new RuntimeException(t.getMessage(), t);
        }

        return super.newFolder(folderName);
    }
};

这样可以确保TemporaryFolder被正确初始化,无论@Before方法是在规则之前还是之后运行。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接