在 1 个测试方法中使用 junit @Rule、expectMessage()、匹配器处理多个异常

Using junit @Rule, expectMessage(), matcher for multipe exception in 1 tested method

在我的 Android 项目中,我想使用相同的 @Test 测试一个 class 可以多次抛出不同消息的相同异常。 我希望我的测试通过给定的消息列表并通过其他消息列表。

对 Junit 进行了一些研究,我尝试使用 @RuleexpectMessage()Hamcrest matcher.

来实现它

我的实施目前基于 "Custom matcher" 描述的 here

@RunWith(AndroidJUnit4.class)
public class TestException extends ApplicationTestCase {

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

    public TestException(){
        super(AplicatyApplication.class);
    }

    @Test
    public void testException() throws Exception {
        thrown.expect(IndexOutOfBoundsException.class);
        thrown.expectMessage(new MatchesPattern("*"));
        Dummy.exec(0);
        // do more stuff here ...
        Dummy.exec(1);
        // ...
        Dummy.exec(2);
        // ...
        Dummy.exec(3); // I want my test to fail here
        // ...
    }

    class MatchesPattern extends TypeSafeMatcher<String> {
        private String pattern;

        public MatchesPattern(String pattern) {
            this.pattern = pattern;
        }

        @Override
        protected boolean matchesSafely(String item) {
            return item.matches(pattern)
                    &&
                    item.startsWith("My message")
                    && (
                        item.endsWith("1")
                        ||
                        item.endsWith("2")
                    );
        }

        @Override
        public void describeTo(Description description) {
            description.appendText("matches pattern ").appendValue(pattern);
        }

        @Override
        protected void describeMismatchSafely(String item, Description mismatchDescription) {
            mismatchDescription.appendText("does not match");
        }
    }

    static class Dummy {
        static void exec(int i){
            if(i == 0)
                return;
            if(i == 1)
                throw new IndexOutOfBoundsException("My message1");
            if(i == 2)
                throw new IndexOutOfBoundsException("My message2");
            if(i == 3)
                throw new IndexOutOfBoundsException("My message3");
        }
    }
}

运行 这个测试我可以看到匹配器只被调用一次,执行 Dummy.exec(1);.

matchesSafely(String item) returns true 并且测试以状态 通过 结束。 根据我对@Rule 的理解,所有这些似乎都可以。我在等待一个例外:我明白了;我正在等待给定的消息:我收到了。

一旦抛出第一个异常,我就找不到继续执行测试的方法。

我的问题是:

我建议将测试方法拆分成多个测试,每个需求一个。

@Test
public void testException_1() throws Exception {
    thrown.expect(IndexOutOfBoundsException.class);
    thrown.expectMessage("My message1");

    Dummy.exec(1);
}

如果它需要在一种测试方法中,我会用 try-catch 和 ErrorCollector 构建它。

@Test
public void testException_1() throws Exception {
    try {
        Dummy.exec(1);
        fail();
    } catch (IndexOutOfBoundsException e) {
        errorCollector.checkThat(e.getMessage(), is("My message1"));
    }

    try {
        Dummy.exec(2);
        ...
    } ...
}

我会尽量避免构建自定义匹配器。