关于java:具有预期异常的JUnit测试不符合预期

JUnit test with expected exception does not behave as anticipated

我遇到了JUnit 4.12的一个问题我在代码中测试一个应该抛出特定异常的方法时无法解释。
我正在使用@Test注释(expected = MyException.class)。
MyException只是从Exception派生而来。

由于编程错误(缺少'throw'子句),不会抛出此异常。由于测试用例设置包括使用jmockit 1.29的模拟类,因此稍后在方法中抛出NullPointerException。

shwoing基本类布局的示例类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package l00tr.test;

public class MyException extends Exception {
    private static final long serialVersionUID = 1L;
    public MyException(String msg) {
        super(msg);
    }
}

package l00tr.test;

import java.util.Map;
import java.util.Set;

public class MyClass {

    private Set<String> testSet;
    private Map<String, String> testMap;
    private boolean condition;

    private MyClass() {
        this.testSet = null;
        this.testMap = null;
        this.condition = false;
    }
    private MyClass(Set<String> testSet, Map<String, String> testMap,
            boolean condition) {
        this.testSet = testSet;
        this.testMap = testMap;
        this.condition = condition;
    }
    public void method() throws MyException {
        if (testSet.size() < 2) {
            throw new MyException("test set");
        }
        if (!condition) {
            // FORGOTTEN: throw
            new MyException("test");
        }
        System.out.print("set size:" + testSet.size());
        System.out.print("some more stuff succeeding");
        System.out.print("map size:" + testMap.size()); // NullPointerException
    }
    public static final class Builder {
        private Set<String> testSet;
        private Map<String, String> testMap;
        private boolean condition;
        private Builder() {
            this.testSet = null;
            this.testMap = null;
            this.condition = false;
        }
        public static Builder newBuilder() {
            return new Builder();
        }
        public Builder testSet(Set<String> testSet) {
            this.testSet = testSet;
            return this;
        }
        public Builder testMap(Map<String, String> testMap) {
            this.testMap = testMap;
            return this;
        }
        public Builder condition(boolean condition) {
            this.condition = condition;
            return this;
        }
        public MyClass build() {
            return new MyClass(testSet, testMap, condition);
        }
    }
}

所以我希望测试失败。但它确实成功了。删除测试注释的"(expected = ...)"部分会导致测试失败并出现NullPointerException。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package l00tr.test;

import java.util.Set;
import org.junit.Test;
import mockit.Expectations;
import mockit.Mocked;

public class MyClassTests {
    @Mocked
    private Set<String> testSet;

    @Test(expected = MyException.class)
    public void testMethod() throws MyException {
        new Expectations() {
            {
                testSet.size();
                result = 3;
            }
        };
        MyClass mc = MyClass.Builder.newBuilder().condition(false)
                .testSet(testSet).build();
        mc.method();
    }
}

Jacoco帮助发现了这一点,否则我会错误地认为一切都很好。我还检查了junit 4.12的未解决问题,但没有找到匹配的问题。

为什么测试成功?有任何想法吗?

更新:

我改进了示例以显示我的代码的相关细节。不幸的是,上面粘贴的代码确实表现得如预期,即显示错误:

1
java.lang.Exception: Unexpected exception, expected<l00tr.test.MyException> but was<java.lang.NullPointerException>

我的具体开发环境设置可能起作用,所以这里有一些细节:

  • gradle 3.2.1 with active daemon
  • junit 4.12
  • jmockit 1.29
  • eclipse Neon.1a发布(4.6.1)
  • java版"1.8.0_112"64位
  • Windows 10


在有用的评论之后,我发现问题可以缩小到"使用Junit4进行基于注释的异常检查的'误报'问题":

在再次检查完整的堆栈跟踪和包含抽象超类的代码之后,我发现try / catch在记录后将任何异常转换为MyException。 因此,从工具和代码的角度来看,一切都是可以预期的。