如何使用 google-truth 测试是否抛出了预期的异常?
How to test that an expected exception is being thrown using google-truth?
我只想测试是否使用 google-truth 抛出了给定消息的异常。
使用 junit 使用 @Test(expected=
很容易做到这一点,但我不知道如何用 truth 做到这一点。 ThrowableSubject.
附近没有样本
对于这类测试,我应该坚持使用普通 JUnit
吗?
目前没有内置方法可以用 google-truth
验证预期的 Exception
。您可以执行以下操作之一:
- 使用one of the JUnit approaches,比如你提到的
expected=
- Write 通过用
try...catch
围绕测试的 exercise/act/when 部分来测试 "ugly" 方式,如@c0der 所述,which is what the unit tests for guava
do
- 制作your own fluent assertions, similar to what AssertJ already has,像下面的例子
我相信 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());
}
}
}
}
}
[更新]
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" 问题,并且 returns 一个可以使用 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 块那样容易进行静态分析。
作为此处的更新,我们已经摆脱了 Christian 描述的模式,Issue #219 has been closed in favor of JUnit's expectThrows()
(coming in 4.13, similar methods already exists in TestNG's Assert
)。
与 expectThrows()
串联,您可以使用 Truth 来制作 assertions about the thrown exception。所以克里斯蒂安的例子现在是:
SpecificException expected = expectThrows(
SpecificException.class, () -> doSomethingThatThrows());
assertThat(expected).hasMessageThat().contains("blah blah blah");
我只想测试是否使用 google-truth 抛出了给定消息的异常。
使用 junit 使用 @Test(expected=
很容易做到这一点,但我不知道如何用 truth 做到这一点。 ThrowableSubject.
对于这类测试,我应该坚持使用普通 JUnit
吗?
目前没有内置方法可以用 google-truth
验证预期的 Exception
。您可以执行以下操作之一:
- 使用one of the JUnit approaches,比如你提到的
expected=
- Write 通过用
try...catch
围绕测试的 exercise/act/when 部分来测试 "ugly" 方式,如@c0der 所述,which is what the unit tests forguava
do - 制作your own fluent assertions, similar to what AssertJ already has,像下面的例子
我相信 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());
}
}
}
}
}
[更新]
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" 问题,并且 returns 一个可以使用 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 块那样容易进行静态分析。
作为此处的更新,我们已经摆脱了 Christian 描述的模式,Issue #219 has been closed in favor of JUnit's expectThrows()
(coming in 4.13, similar methods already exists in TestNG's Assert
)。
与 expectThrows()
串联,您可以使用 Truth 来制作 assertions about the thrown exception。所以克里斯蒂安的例子现在是:
SpecificException expected = expectThrows(
SpecificException.class, () -> doSomethingThatThrows());
assertThat(expected).hasMessageThat().contains("blah blah blah");