junit 如何使用google-truth测试预期的异常被抛出?

e4eetjau  于 2023-06-23  发布在  Go
关注(0)|答案(4)|浏览(140)

我只是想测试一个带有给定消息的异常是否正在使用google-truth抛出。
使用junit使用@Test(expected=很容易做到这一点,但我无法弄清楚如何用truth做到这一点。ThrowableSubject周围没有样本。
我应该坚持使用普通JUnit来进行这些测试吗?

qpgpyjmq

qpgpyjmq1#

[更新]
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,因为它更简洁,避免了“missing fail”问题,并返回一个可以使用Truth中的ThrowableSubjectAssert的对象。
如果您没有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");
}

虽然JUnit中存在@Rule ExpectedException@Test(exception=...),但Truth团队并不推荐它们,因为它们有一些微妙(或不那么微妙)的方法可以编写通过但应该失败的测试。
虽然try/fail/catch也是如此,但Google在内部使用error-prone来缓解这一问题,它提供了一个静态编译时检查,以确保此模式不会忽略fail()等。强烈建议您使用易错检查或其他静态分析检查来捕获这些错误。遗憾的是,基于规则和基于注解的方法不像这个try/catch块那样容易进行静态分析。

p4rjhz4m

p4rjhz4m2#

作为这里的更新,我们已经摆脱了Christian描述的模式,并且Issue #219已经被关闭,转而支持JUnit的expectThrows()(在4.13中,TestNG的Assert中已经存在类似的方法)。
expectThrows()一起,您可以使用Truth来生成assertions about the thrown exception。所以克里斯蒂安的例子现在是:

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

3b6akqbq3#

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

  • 使用one of the JUnit approaches,如expected=,正如您提到的
  • try...catch包围测试的exercise/act/when部分来编写“丑陋”的测试,正如@c0der提到的,这就是guava的单元测试所做的
  • 创建您自己的流畅Assert,类似于AssertJ已经拥有的,如下面的示例

我相信google-truth没有任何类似的功能,因为它支持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());
                }
            }
        }
    }
}
x33g5p2x

x33g5p2x4#

我并不热衷于只为assertThrows添加JUnit依赖项,特别是因为我正在使我的Jar发行版在运行时进行自测试,所以测试框架就在其中。
我目前正在使用:

try {
    [Manipulate object "o"]
    assertWithMessage("Manipulating %s should have thrown an UnsupportedOperationException", o).fail();
} catch (UnsupportedOperationException expected) {
   
 assertThat(expected.getMessage()).isEqualTo("<message>");
}

相关问题