【问题标题】:How to test that an expected exception is being thrown using google-truth?如何使用 google-truth 测试是否抛出了预期的异常?
【发布时间】:2016-07-18 10:47:10
【问题描述】:

我只想测试是否使用 google-truth 引发了带有给定消息的异常。

使用 @Test(expected= 使用 junit 很容易做到这一点,但我无法弄清楚如何做到这一点。 ThrowableSubject周围没有样本。

我应该坚持使用普通的JUnit 进行此类测试吗?

【问题讨论】:

    标签: java junit google-truth


    【解决方案1】:

    [更新]

    The Truth 作者推荐使用 JUnit 4.13/5 的 assertThrows() 机制,因为这并不需要 Truth 的支持。这看起来更像:

    SpecificException e = 
        assertThrows(SpecificException.class, () -> doSomethingThatThrows());
    assertThat(e).hasMessageThat().contains("blah blah blah");
    assertThat(e).hasCauseThat().isInstanceOf(IllegalStateException.class);
    assertThat(e).hasCauseThat().hasMessageThat().contains("blah");
    

    推荐使用 try/fail/catch,因为它更简洁,避免了“丢失失败”问题,并返回一个可以在 Truth 中使用 ThrowableSubject 断言的对象。

    如果您没有assertThrows(),那么请使用 try/fail/catch 模式,因为这是清晰明确的。

    try {
      doSomethingThatThrows(); 
      fail("method should throw");
    } catch (SpecificException e) {
      // ensure that e was thrown from the right code-path
      // especially important if it's something as frequent
      // as an IllegalArgumentException, etc.
      assertThat(e).hasMessage("blah blah blah");
    }
    

    虽然 @Rule ExpectedException@Test(exception=...) 存在于 JUnit 中,但 Truth 团队不推荐这些,因为它们有一些微妙(和不太微妙)的方式可以编写通过但应该失败的测试。

    虽然 try/fail/catch 也是如此,但 Google 在内部通过使用 error-prone 来缓解这种情况,它提供静态编译时检查以确保此模式不会省略 fail() 等. 强烈建议您使用容易出错或其他静态分析检查来捕获这些。遗憾的是,基于规则和基于注释的方法不像这个 try/catch 块那样容易进行静态分析。

    【讨论】:

    • fail() 在什么类/包中?
    • junit5 中的assertThrows 怎么样?我一直在用 google-truth 使用它,它似乎工作得很好。
    • 这就是谷歌主要使用的,通过功能的反向端口到junit4。
    • 答案更新反映团队现在基本推荐assertThrows()
    【解决方案2】:

    作为这里的更新,我们已经远离 Christian 描述的模式,并且 Issue #219 已关闭以支持 JUnit 的 expectThrows()(在 4.13 中出现,TestNG's Assert 中已经存在类似的方法)。

    expectThrows() 配合使用,您可以使用 Truth 生成assertions about the thrown exception。所以现在克里斯蒂安的例子是:

    SpecificException expected = expectThrows(
        SpecificException.class, () -> doSomethingThatThrows());
    assertThat(expected).hasMessageThat().contains("blah blah blah");
    

    【讨论】:

    • 我更新了我的答案以反映此信息。我相信expectThrows已经被重命名为assertThrows,但这基本上是正确的。
    【解决方案3】:

    目前没有内置方法来验证预期的Exceptiongoogle-truth。您可以执行以下操作之一:

    我相信google-truth 没有任何类似的功能,因为它supports Java 1.6

    import com.google.common.truth.FailureStrategy;
    import com.google.common.truth.Subject;
    import com.google.common.truth.SubjectFactory;
    import org.junit.Test;
    
    import java.util.concurrent.Callable;
    
    import static com.google.common.truth.Truth.assertAbout;
    
    public class MathTest {
        @Test
        public void addExact_throws_ArithmeticException_upon_overflow() {
            assertAbout(callable("addExact"))
                .that(() -> Math.addExact(Integer.MAX_VALUE, 1))
                .willThrow(ArithmeticException.class);
        }
    
        static <T> SubjectFactory<CallableSubject<T>, Callable<T>> callable(String displaySubject) {
            return new SubjectFactory<CallableSubject<T>, Callable<T>>() {
                @Override public CallableSubject<T> getSubject(FailureStrategy fs, Callable<T> that) {
                    return new CallableSubject<>(fs, that, displaySubject);
                }
            };
        }
    
        static class CallableSubject<T> extends Subject<CallableSubject<T>, Callable<T>> {
            private final String displaySubject;
    
            CallableSubject(FailureStrategy failureStrategy, Callable<T> callable, String displaySubject) {
                super(failureStrategy, callable);
                this.displaySubject = displaySubject;
            }
    
            @Override protected String getDisplaySubject() {
                return displaySubject;
            }
    
            void willThrow(Class<?> clazz) {
                try {
                    getSubject().call();
                    fail("throws a", clazz.getName());
                } catch (Exception e) {
                    if (!clazz.isInstance(e)) {
                        failWithBadResults("throws a", clazz.getName(), "throws a", e.getClass().getName());
                    }
                }
            }
        }
    }
    

    【讨论】:

    • 我们正在为 Java8 寻找更健壮的东西,但会更少。类似于assertThat(() -&gt; runMethod()).throws(Throwable.class).withMessage("blah");
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-11
    • 2014-05-09
    • 2021-08-25
    • 2021-02-26
    • 1970-01-01
    • 2017-10-28
    • 2019-11-26
    相关资源
    最近更新 更多