JUnit @Rule взаимодействие с жизненным циклом @Before - PullRequest
11 голосов
/ 12 октября 2011

У меня есть несколько тестов JUnit, которые используют TemporaryFolder @Rule. Они используют TemporaryFolder в методе @Before для выполнения некоторых настроек:

@Rule
public TemporaryFolder folder = new TemporaryFolder();

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

@Test
public void myTest() { ... }

В большинстве случаев это работает отлично. Однако при использовании SpringJUnit4ClassRunner я обнаружил, что в некоторых случаях метод init() вызывается до применения Statement внутри моего экземпляра TemporaryFolder. Из-за этого местоположение временной папки не устанавливается (то есть: null), когда folder используется в init() и мой файл попадает в рабочий каталог, а не /tmp.

Так что в некоторых случаях @Before методы выполняются с опережением правил, однако я не могу установить определенный шаблон. Иногда я вижу похожую проблему с некоторыми из моих собственных реализаций правил.

Можно ли как-нибудь гарантировать, что мои правила будут применены перед любыми методами настройки?

Ответы [ 2 ]

12 голосов
/ 14 октября 2011

В 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= 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;

Родительское POM spring-test-3.0.5, похоже, указывает на то, что оно зависит от JUnit 4.7. Интересно, поможет ли использовать его более новый JUnit?

0 голосов
/ 09 июля 2013

Что бы это ни стоило, я использовал следующее в качестве быстрого обходного пути:

@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или после правил.

...