在Android Espresso测试中断言异常
问题描述:
我在Espresso中进行了一项测试,该测试需要断言某个操作会引发异常.
I have a test in Espresso that needs to assert that a certain action cause an exception to be thrown.
然而,Espresso框架似乎吞下了原始异常,只出现了一个 PerformException
.
However it seems that the Espresso framework swallows the original exception and only surfaces a PerformException
.
答
最终,我找到了一种方法.我创建了一个自定义的Hamcrest匹配器,可让您验证嵌套异常.
Eventually I found a way to do it. I've created a custom Hamcrest matcher that allows you to verify a nested exception.
public class NestedExceptionMatcher extends TypeSafeMatcher<Throwable> {
private final Class<?> mExpectedType;
private final Matcher<String> mMessageMatcher;
static NestedExceptionMatcher expectNestedThrowable(Class<?> expectedType, Matcher<String> messageMatcher) {
return new NestedExceptionMatcher(expectedType, messageMatcher);
}
NestedExceptionMatcher(Class<?> expectedType, Matcher<String> messageMatcher) {
mExpectedType = expectedType;
mMessageMatcher = messageMatcher;
}
@Override
protected boolean matchesSafely(Throwable item) {
boolean matches = isMatch(item);
Throwable currentThrowable = item.getCause();
while (!matches && currentThrowable != null) {
matches = isMatch(currentThrowable);
currentThrowable = currentThrowable.getCause();
}
return matches;
}
@Override
public void describeTo(Description description) {
description
.appendText("expects type ")
.appendValue(mExpectedType)
.appendText(" with a message ")
.appendDescriptionOf(mMessageMatcher);
}
private boolean isMatch(Throwable t) {
return t.getClass().isAssignableFrom(mExpectedType) && mMessageMatcher.matches(t.getMessage());
}
}
然后您可以在测试中按如下方式使用它:
And then you can use it as follows in your test:
public class SomeActivityTest {
@Rule
public ActivityTestRule<SomeActivity> mRule = new ActivityTestRule<>(
SomeActivity.class, false, false);
@Rule
public ExpectedException mExceptionRule = ExpectedException.none();
@Test
public void testClick_whenInvalidParamsAreSet_shouldThrowException() {
mRule.launchActivity(getIntentWithInvalidParams());
mExceptionRule.expect(expectNestedThrowable(
IllegalArgumentException.class,
containsString("parameter isn't defined")
));
onView(withId(R.id.my_btn)).perform(click());
}
private Intent getIntentWithInvalidParams() {
...
}
}