JUnit测试使用ExpectedException和TestWatcher@Rule#39通过和失败冲突;s[英] JUnit Test both passes and fails - conflict using both ExpectedException and TestWatcher @Rule's

问题描述

我在提出这个问题时发现了这一点,但认为这对于未来遇到同样奇怪怪癖的人来说是一个很好的资源.将其视为对您调试技能的挑战.

使用目前最新的 JUnit 4.12,这个特殊的测试既通过也失败 - 取决于您如何看待它.运行它会打印出错误消息 - 但尽管调用了 failed(),它仍然不会完全算作失败.

import java.io.IOException;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;

public class TestWatcherExpectedExceptionTest {
    @Rule
    public TestWatcher logger = new TestWatcher() {
        @Override
        protected void failed(Throwable e, Description d) {
            System.out.println(d + " FAILED! - are you kidding me ?");
            e.printStackTrace();
        }

        @Override
        protected void succeeded(Description d) {
            System.out.println(d + " succeeded!");
        }
    };

    @Rule
    public ExpectedException thrown = ExpectedException.none();

    /**
     * This test both passes and fails, depending how you look at it.
     */
    @Test
    public void photon() throws IOException {
        thrown.expect(IOException.class);
        throw new IOException("Hi");
    }
}

作为一个额外的问题,在调试这个问题的过程中,测试突然开始成功,并调用了 succeeded() 方法,我一生都无法弄清楚为什么.据我所知,代码没有任何更改可能会产生任何影响:

import java.io.IOException;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;

public class TestWatcherExpectedExceptionTest {
    private final class TestLogger extends TestWatcher {
        @Override
        protected void failed(Throwable e, Description d) {
            System.out.println(d + " FAILED! - are you kidding me ?");
            e.printStackTrace();
        }

        @Override
        protected void succeeded(Description d) {
            System.out.println(d + " succeeded!");
        }
    }

    @Rule
    public TestWatcher watcher = new TestLogger();

    @Rule
    public ExpectedException thrown = ExpectedException.none();

    /**
     * This test both passes and fails, depending how you look at it.
     */
    @Test
    public void photon() throws IOException {
        thrown.expect(IOException.class);
        throw new IOException("Hi");
    }
}

推荐答案

为什么第二个测试有效,为什么第一个测试失败的特殊答案在于 JUnit 处理规则的方式 - 显然,规则是按字母顺序处理的基于字段名称的顺序,并且 TestWatcher 规则与 ExpectedException 规则不太兼容,因为如果 JUnit 过早地"解释"该规则,它会忽略预期的异常.

所以第二个测试没有失败的原因在于字段名称 - watcher 按字母顺序位于 thrown 之后,但第一个测试的字段名称 logger 位于 thrown 之前.那个调试起来不好玩.

本文地址:https://www.itbaoku.cn/post/978605.html