JUnit Test传递和失败 - 使用ExpectedException和TestWatcher @ Rule进行冲突

时间:2017-03-29 08:43:09

标签: 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");
    }
}

1 个答案:

答案 0 :(得分:2)

为什么第二个测试工作的原因以及为什么第一个测试完全失败的原因在于JUnit处理规则的方式 - 显然,规则是按字母顺序处理的,基于字段名称和{{1} }规则与public bool ClassNameContainString<T>(string text) where T : class { var containsString = typeof(T).ToString().Contains(text); return containsString; } 规则不完全兼容,因为如果规则被JUnit过早“解释”,它将忽略预期的异常。

因此,第二个测试没有失败的原因在于字段名称 - var containsString = typeof(T).ToString().ToLower().Contains(text.ToLower()); TestWatcher之后按字母顺序排列,但第一个测试的字段名称ExpectedException出现在{{ 1}}。那个调试并不好玩。