使用非强制异常使java中的junit测试成功

3phpmpom  于 2022-11-11  发布在  Java
关注(0)|答案(2)|浏览(137)

我正在寻找一种方法,通过一个自定义异常导致一个成功,而不是在junit4中一直期待它。这是否可能与一个testrule或其他东西,而不触及每一个测试用例?
我知道这些选项是存在的,但是如果没有抛出异常,那么异常是预期的,测试失败。我希望即使没有抛出异常,测试也能继续,并且在一些特殊情况下通过aspectj使用异常来结束测试。
第一个

piah890a

piah890a1#

就junit4的源代码而言,还没有一种方法可以实现这一点,我找到的唯一方法是定制runner本身。
所以是这样的:

public class CustomTestRunner extends Runner {
    private Class testClass;

    public CustomTestRunner(Class testClass) {
        super();
        this.testClass = testClass;
    }

    @Override
    public Description getDescription() {
        return Description.EMPTY;
    }

    @Override
    public void run(RunNotifier notifier) {
        // Load all methods with @Test annotation from the given class and fire the execution
        try {
            Object testObject = testClass.getConstructor().newInstance();
            for (Method method : testClass.getMethods()) {
                if (method.isAnnotationPresent(Test.class)) {
                    fire(notifier, testObject, method);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void fire(RunNotifier notifier, Object testObject, Method method) throws IllegalAccessException, InvocationTargetException {
        notifier.fireTestStarted(Description
                .createTestDescription(testClass, method.getName()));

        try {
            // Call the test method
            method.invoke(testObject);
        } catch (InvocationTargetException e) {
            // method.invoke wraps the original exception with InvocationTargetException
            // The original exception is accessible via getCause()
            // Check if the type of the original exception is the custom "early exist" exception
            // If it doesn't match, throw the exception again; otherwise, ignore and mark the test as successful
            if (!(e.getCause() instanceof EndTestEarlyException)) {
                throw e;
            }
        }

        notifier.fireTestFinished(Description
                .createTestDescription(testClass, method.getName()));
    }
}

您可以通过如下注解Test类来使用它:

@RunWith(CustomTestRunner.class)
class MyIntegrationTest {
...
}

注:运行程序是最通用的运行程序。如果您已经使用了一个运行程序,也可以尝试覆盖一个更具体的运行程序。
编辑:由于您正在使用legacy,我有意尝试不使用较新的语言特性,如泛型(Class<?>)。
该解决方案基于this baeldung文章。
六月五日
最后但同样重要的是:这可能与您的特定情况无关,但对未来的读者可能会感兴趣。如果您设法升级到Junit5,您可以在扩展中处理此问题。
您可以像这样实现自定义扩展:

public class IgnoreEndTestEarlyException implements TestExecutionExceptionHandler {
    @Override
    public void handleTestExecutionException(ExtensionContext context,
      Throwable throwable) throws Throwable {

        if (throwable instanceof EndTestEarlyException ) {
            return;
        }

        throw throwable;
    }
}

并像这样使用它:

@ExtendWith(IgnoreEndTestEarlyException.class)
public class MyIntegrationTest

我倾向于创建另一个注解(类似于@IntegrationTest),将@ExtendsWith放在那里,然后使用新的注解。
添加多个扩展会更简洁、更容易。您可以在同一个模块中运行Junit4和Junit5,但是您必须替换集成测试套件中的所有注解。对于数千个测试来说,这可能不值得。

6mzjoqzu

6mzjoqzu2#

对于Junit4,我找到了一个更好的解决方案。只需覆盖BlockJUnit4ClassRunner中的runChild方法,并为EndTestEarlyException添加一个try catch。

@Override
    protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
        Description description = describeChild(method);
        if (isIgnored(method)) {
            notifier.fireTestIgnored(description);
        } else {
            Statement statement = new Statement() {
                @Override
                public void evaluate() throws Throwable {
                    try {
                        methodBlock(method).evaluate();
                    } catch (EndTestEarlyException e) {
                        System.out.println("EndTestEarlyException - ignore");
                    }
                }
            };
            runLeaf(statement, description, notifier);
        }
    }

相关问题