Ответ 1
Если вам посчастливилось использовать JUnit 4.9 или новее, TestWatcher
будет делать именно то, что вы хотите.
Поделитесь и наслаждайтесь!
Есть ли способ в JUnit обнаружить внутри @After аннотированный метод, если в тестовом случае произошел сбой или ошибка теста?
Одно уродливое решение будет примерно таким:
boolean withoutFailure = false;
@Test
void test() {
...
asserts...
withoutFailure = true;
}
@After
public void tearDown() {
if(!withoutFailuere) {
this.dontReuseTestenvironmentForNextTest();
}
}
Это некрасиво, потому что нужно обязательно следить за "инфраструктурой" (без флага флага) в тестовом коде.
Я надеюсь, что есть что-то, где я могу получить статус теста в методе @After!?
Если вам посчастливилось использовать JUnit 4.9 или новее, TestWatcher
будет делать именно то, что вы хотите.
Поделитесь и наслаждайтесь!
Я расширяю dsaff-ответ, чтобы решить проблему, что TestRule
не может выполнить какой-либо код, сбрасываемый между выполнением тестового метода и методом after-method. Таким образом, с помощью простого MethodRule
нельзя использовать это правило, чтобы обеспечить флаг успеха, который используется в аннотированных методах @After
.
Моя идея - взломать! В любом случае, нужно использовать TestRule
(extends TestWatcher
). A TestRule
получит информацию о неудачном или успешном тестировании. Мой TestRule
затем сканирует класс для всех методов, аннотированных моими новыми аннотациями AfterHack
, и вызовет эти методы с флагом успеха.
AfterHack
аннотация
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(METHOD)
public @interface AfterHack {}
AfterHackRule
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
public class AfterHackRule extends TestWatcher {
private Object testClassInstance;
public AfterHackRule(final Object testClassInstance) {
this.testClassInstance = testClassInstance;
}
protected void succeeded(Description description) {
invokeAfterHackMethods(true);
}
protected void failed(Throwable e, Description description) {
invokeAfterHackMethods(false);
}
public void invokeAfterHackMethods(boolean successFlag) {
for (Method afterHackMethod :
this.getAfterHackMethods(this.testClassInstance.getClass())) {
try {
afterHackMethod.invoke(this.testClassInstance, successFlag);
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
throw new RuntimeException("error while invoking afterHackMethod "
+ afterHackMethod);
}
}
}
private List<Method> getAfterHackMethods(Class<?> testClass) {
List<Method> results = new ArrayList<>();
for (Method method : testClass.getMethods()) {
if (method.isAnnotationPresent(AfterHack.class)) {
results.add(method);
}
}
return results;
}
}
Использование:
public class DemoTest {
@Rule
public AfterHackRule afterHackRule = new AfterHackRule(this);
@AfterHack
public void after(boolean success) {
System.out.println("afterHack:" + success);
}
@Test
public void demofails() {
Assert.fail();
}
@Test
public void demoSucceeds() {}
}
BTW:
@see
Я думаю, что вам нужно будет добавить RunListener в ядро JUnit. Затем вы можете переопределить метод testFailure
, чтобы установить флаг withoutFailure
в одном месте, чтобы вы могли проверить его в своем аннотированном методе @After
.
Также см.: это сообщение в блоге для обсуждения некоторых проблем с этим подходом при использовании более ранних версий JUnit.
Я не знаю простого или элегантного способа обнаружить сбой теста Junit в методе @After.
Если можно использовать TestRule вместо метода @After, одна из возможностей сделать это - использовать два закодированных TestRules, используя TestWatcher в качестве внутреннего правила.
Пример:
package org.example;
import static org.junit.Assert.fail;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExternalResource;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
public class ExampleTest {
private String name = "";
private boolean failed;
@Rule
public TestRule afterWithFailedInformation = RuleChain
.outerRule(new ExternalResource(){
@Override
protected void after() {
System.out.println("Test "+name+" "+(failed?"failed":"finished")+".");
}
})
.around(new TestWatcher(){
@Override
protected void finished(Description description) {
name = description.getDisplayName();
}
@Override
protected void failed(Throwable e, Description description) {
failed = true;
}
})
;
@Test
public void testSomething(){
fail();
}
@Test
public void testSomethingElse(){
}
}
RuleChain не работает. Метод @After все еще выполняется и завершается до того, как метод TestWatcher завершился с ошибкой. Это не помогает.
Мне также нужно найти способ сделать что-то сначала внутри @After или перед @After, если тест не пройден. Правило и все подходы TestWatcher здесь не работают.