Подтвердить что ты не робот

JUnit @Rule жизненный цикл взаимодействия с @Before

У меня есть тесты 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. Из-за этого временное расположение папки не задано (i.e: null), когда folder используется в init(), а мой файл заканчивается в рабочем каталоге, а не /tmp.

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

Есть ли способ, которым я могу гарантировать, что мои инструкции правил применяются до любых методов настройки?

4b9b3361

Ответ 1

В JUnit 4.10 BlockJUnit4ClassRunner (суперкласс SpringJUnit4ClassRunner), по-видимому, позаботится о построении цепочек операторов таким образом, что правила запускаются перед любыми методами @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;

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

Ответ 2

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

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