在自定义字段中使用特定条件声明预期的异常

时间:2020-01-21 14:39:25

标签: java junit junit4 hamcrest

我想验证预期的例外是否符合某些条件。以此为起点:

class MyException extends RuntimeException {
    int n;
    public MyException(String message, int n) {
        super(message);
        this.n = n;
    }
}

public class HowDoIDoThis {
    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Test
    public void test1() {
        thrown.expect(MyException.class);
        throw new MyException("x", 10);
    }
}

例如,如何断言所引发的异常具有n > 1并且message仅包含小写字母?我当时在考虑使用thrown.expect(Matcher),但无法弄清楚如何使Hamcrest匹配器检查对象的任意字段。

3 个答案:

答案 0 :(得分:1)

您可以使用TypeSafeMatcher来提供MyException类,然后使用IntPredicate根据条件检查n的值:

public class MyExceptionMatcher extends TypeSafeMatcher<MyException> {
    private final IntPredicate predicate;

    public MyExceptionMatcher(IntPredicate predicate) {
        this.predicate = predicate;
    }

    @Override
    protected boolean matchesSafely(MyException item) {
        return predicate.test(item.n);
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("my exception which matches predicate");
    }
}

那么您可以期望这样:

thrown.expect(new MyExceptionMatcher(i -> i > 1));

答案 1 :(得分:1)

Hamcrest中还有FeatureMatcher,非常适合为对象的嵌套“特征”创建匹配器。因此,在您的示例中,您可以通过以下方式使用FeatureMatcher来构造它(这是我为嵌套字段创建匹配器时倾向于遵循的模式):

public final class MyExceptionMatchers {

    public static Matcher<MyException> withNthat(Matcher<Integer> nMatcher) {
        return new FeatureMatcher<MyException, Integer>(nMatcher, "n", "n") {
              @Override
              protected Integer featureValueOf(MyException actual) {
                   return actual.n;
              }
        }
    }
}

在测试中:

import static x.y.z.MyExceptionMatchers.withNthat;
import static org.hamcrest.Matchers.greaterThan;

...

thrown.expect(withNThat(greaterThan(1)));

采用这种布局,可以很容易地为MyException添加更多匹配器,并且感觉更像是一种“规范”的方法来构建可组合的匹配器,从而使您可以为测试用例构建所需的精确匹配器。

答案 2 :(得分:0)

一种简洁明了的替代方法是使用AssertJ而不是ExpectedException规则。

    assertThatThrownBy(() -> {
        throw new MyException("x", 10);
    })
        .matches(e -> e.getMessage().equals(e.getMessage().toLower()), "message is lowercase")
        .matches(e -> ((CustomException) e).n > 10, "n > 10");
相关问题