【问题标题】:Is it possible to access instance of exception "catched" with JUnit Rule ExpectedException?是否可以使用 JUnit Rule ExpectedException 访问“捕获”的异常实例?
【发布时间】:2020-01-28 10:33:10
【问题描述】:

假设在一个测试中是:

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

一些测试包含:

thrown.expect(SomeNastyException.class);

现在如果需要更详细地检查这个SomeNastyException,该怎么做?

当然可以不使用ExcpectedException 并用 try/catch 包装调用,然后以任何需要的方式检查异常,但现在的问题是它是否可以完成与ExpectedException,类似:

assertEquals("42", thrown.getException().getUniversalAnswerToEverything());

【问题讨论】:

  • 不简单;规则基本上就是为此而存在的语法糖。这是我强烈喜欢 Spock 而不是普通的 JUnit 的众多原因之一。
  • @chrylis-onstrike-,您可以期待 JUnit 中带有消息或原因的特定异常。通过使用expect(Matcher<?>) 覆盖。在这方面,Spock 比 JUnit 没有任何优势。

标签: java exception junit assert rules


【解决方案1】:

在该规则中有一个不太专业的 expect 方法版本,它接受 Hamcrest 的匹配器:

expect(Matcher)

只要有一个Matcher 实现,这个方法就可以让你断言几乎所有关于抛出异常的东西。

例如,对于您的情况,它看起来像这样:

import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.is;

....

exceptions.expect(hasProperty("UniversalAnswerToEverything", is(42)));

Hamcrest 有一个非常灵活的匹配器模型,因此如果您对库中包含的内容不满意,也可以轻松编写自己的匹配器模型。

【讨论】:

    【解决方案2】:

    您可以使用 hasProperty hamcrest 匹配器。如果您的 SomeNastyException 不符合 java bean 协议,您可以为您的异常创建自定义 hamcrest 匹配器:

    package stackoverflow.q59946794;
    
    import org.hamcrest.Description;
    import org.hamcrest.FeatureMatcher;
    import org.hamcrest.Matcher;
    import org.hamcrest.TypeSafeMatcher;
    import org.hamcrest.core.IsEqual;
    import org.junit.Rule;
    import org.junit.Test;
    import org.junit.rules.ExpectedException;
    
    import java.util.logging.Logger;
    
    public class SomeNastyExceptionSpec {
        private final static Logger logger = Logger.getLogger(SomeNastyExceptionSpec.class.getName());
    
        public static class SomeNastyException extends Exception implements java.io.Serializable {
            SomeNastyException(String message) { super(message);}
            public Integer getUniversalAnswerToEverything() {return 42;}
        }
    
        public static Matcher<SomeNastyException> hasUniversalAnswerToEverythingFeature(final int expectedAnswer) {
            return new FeatureMatcher<SomeNastyException, Integer>(
                    new IsEqual<Integer>(expectedAnswer),
                    "SomeNastyException actual answer",
                    "SomeNastyException expected answer"
            ) {
                @Override
                protected Integer featureValueOf(SomeNastyException actual) {
                    return actual.getUniversalAnswerToEverything();
                }
            };
    
        }
        public static Matcher<SomeNastyException> hasUniversalAnswerToEverything(final int expectedAnswer) {
            return new TypeSafeMatcher<SomeNastyException>() {
    
                @Override
                protected void describeMismatchSafely(SomeNastyException e, Description description) {
                    description.appendText("was ").appendValue(e.getUniversalAnswerToEverything());
                }
    
                @Override
                public void describeTo(Description description) {
                    description.appendText("SomeNastyException with answer ").appendValue(expectedAnswer);
                }
    
                @Override
                protected boolean matchesSafely(SomeNastyException e) {
                    return e.getUniversalAnswerToEverything() == expectedAnswer;
                }
            };
        }
    
        @Rule(order = Integer.MAX_VALUE)
        public ExpectedException thrown = ExpectedException.none();
    
        @Test
        public void shouldTestExceptionMessage() throws Exception {
            thrown.expect(SomeNastyException.class);
            thrown.expect(hasUniversalAnswerToEverything(42));
            thrown.expect(hasUniversalAnswerToEverythingFeature(42));
            thrown.expectMessage("always 42");
            throw new SomeNastyException("always 42");
        }
    }
    
    

    【讨论】:

    • FeatureMatcher 在这方面要好得多。
    【解决方案3】:

    我的问题是在使用 JUnit4 时提出的。最近迁移到 JUnit5,它正是我想要的,即返回抛出异常的assertThrows。作为一个虚拟示例:

    @org.junit.jupiter.api.Test
    void testThrows() {
        Exception exception = assertThrows(NotAnswerableException.class, () -> {
            throw new NotAnswerableException("please rephrase your question", param2, param3);
        });
        assertTrue(exception.getMessage().startsWith("please"));
        assertEquals(param2, exception.getParam2());
    }
    

    【讨论】:

      猜你喜欢
      • 2011-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多