java - JUnit 测试既通过又失败 - 使用 ExpectedException 和 TestWatcher @Rule's 发生冲突

标签 java unit-testing junit

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

目前使用最新的 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 之前。那个调试起来并不有趣。

关于java - JUnit 测试既通过又失败 - 使用 ExpectedException 和 TestWatcher @Rule's 发生冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43088543/

相关文章:

java - Bean 验证 - JSR-303 DuplicateItemCheck for a list in java

python - Django reset_sequences 在 LiveServerTestCase 中不起作用

mysql - 用 Jest 模拟 mysql 连接

java - Mockito inOrder.verify() 失败 - "Wanted but not invoked ... wanted anywhere AFTER following interaction"

java - 如何使用Java生成20个唯一且有顺序的随机数?

java - 同步 ID 并删除

java - 从外部中止 JUnit 线程

java - 自定义调用 TestSuite 的多个 TestExecutionListeners 方法的最佳方法是什么?

java - 如何在Android Studio中显示几分钟后显示隐藏内容

python - pytest:参数化测试与显式测试