如何进行第3次测试以检查异常消息中是否存在cause1?我还列出了前两个有缺点的测试。首先是不检查第二个需要大量样板代码的消息。
public class CheckExceptionsWithMockitoTest {
@Test(expected = RuntimeException.class)
public void testExpectedException1() {
A a = new A();
a.doSomethingThatThrows();
}
@Test
public void testExpectedException2() {
A a = new A();
try {
a.doSomethingThatThrows();
fail("no exception thrown");
} catch (RuntimeException e) {
assertThat(e.getMessage(), org.hamcrest.Matchers.containsString("cause1"));
}
}
@Test
public void testExpectedException3() {
A a = new A();
A spyA = org.mockito.Mockito.spy(a);
// valid but doesnt work
// doThrow(new IllegalArgumentException()).when(spyA).doSomethingThatThrows();
// invalid but in the spirit of what i want
//chekThrow(RuntimeException.class,containsString("cause1")).when(spyA).doSomethingThatThrows();
}
}
我在Mockito中找不到有效的东西,但有些东西看起来可能(在语法层面)和功能。
使用catchexception我创建了这样的测试
import static com.googlecode.catchexception.CatchException.*;
import static com.googlecode.catchexception.apis.CatchExceptionHamcrestMatchers.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import org.junit.*;
public class CheckExceptionsWithMockitoTest{
//...
@Test
public void testExpectedException3() {
A a = new A();
verifyException(a,IllegalArgumentException.class)
.doSomethingThatThrows();
//if more details to be analized are needed
assertThat(
(IllegalStateException) caughtException(),
allOf(
is(IllegalStateException.class),
hasMessageThat(
containsString("is not allowed to add counterparties")),
hasNoCause()));
//more asserts could come
assertNotNull(a);
}
}
答案 0 :(得分:5)
使用catch-exception库,或者我猜你正在寻找的解决方案是你的第二个实现。
@expected没有提供任何方法来断言抛出的异常,除了它的类,所以你不能避免尝试/捕获(没有那么多的样板代码!)
Mockito不提供类似 verifyThrows 方法的内容。
因此,您可以交换尝试/捕获其他库:使用catch-exception,您将能够在一行中捕获异常并准备好进一步断言。
A a = new A();
when(a).doSomethingThatThrows();
then(caughtException())
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("is not allowed to add counterparties")
.hasNoCause();
'com.googlecode.catch-exception:catch-exception:1.2.0'
答案 1 :(得分:4)
如果A
是您正在测试的系统,那么嘲笑它是没有任何意义的,并且窥探它很少有意义。您在testExpectedException2
中的实施是正确的;样板代码是必要的,因为没有try
块,Java将不会在截获方法后运行任何代码(正如我在this previous SO answer中所描述的那样)。
虽然Mockito没有任何帮助,但JUnit会。 @Test(expected=foo)
参数实际上有一个更灵活的选择,即内置ExpectedException
JUnit rule:
public class CheckExceptionsWithMockitoTest {
@Rule public ExpectedException thrown = ExpectedException.none();
@Test
public void testExpectedException1() {
A a = new A();
thrown.expect(RuntimeException.class);
thrown.expectMessage(containsString("cause1"));
a.doSomethingThatThrows();
}
}
Mockito 会在一个单独的测试中派上用场,检查你的方法是否包含一个任意异常,同时保留它的消息,这看起来大致如下:
@Test
public void doSomethingShouldWrapExceptionWithPassedMessage() {
Dependency dependency = Mockito.mock(Dependency.class);
when(dependency.call()).thenThrow(new IllegalArgumentException("quux"));
A a = new A(dependency);
thrown.expect(RuntimeException.class);
thrown.expectMessage(containsString("quux"));
a.doSomethingThatThrows();
}
小心避免在测试中将此作为一种常见模式的诱惑。如果您正在捕获被测系统中抛出的异常,那么您有效地将控制权交还给SUT的消费者。除了异常的属性和MAYBE系统的状态之外,之后应该没有什么可以在方法中进行测试,这两者都应该足够稀少,以便可以原谅try / catch样板。
答案 2 :(得分:1)
如果您有机会使用scala,scalaTest的有趣套件可以使用截距(http://www.scalatest.org/getting_started_with_fun_suite)简洁地测试异常。
它就像
一样简单 test(a list get method catches exceptions){
intercept[IndexOutBoundsException]{
spyListObject.get(-1)
}
}
如果您正在寻找易于编写/清除测试,则可以将您的测试写入scala中的java项目。但这可能会带来其他挑战。
答案 3 :(得分:1)
2015年6月19日更新了答案(如果你正在使用java 8)
使用assertj-core-3.0.0 + Java 8 Lambdas
@Test
public void shouldThrowIllegalArgumentExceptionWhenPassingBadArg() {
assertThatThrownBy(() -> myService.sumTingWong("badArg"))
.isInstanceOf(IllegalArgumentException.class);
}
参考:http://blog.codeleak.pl/2015/04/junit-testing-exceptions-with-java-8.html
答案 4 :(得分:0)
使用catchexception我创建了这样的测试
import static com.googlecode.catchexception.CatchException.*;
import static com.googlecode.catchexception.apis.CatchExceptionHamcrestMatchers.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import org.junit.*;
public class CheckExceptionsWithMockitoTest{
//...
@Test
public void testExpectedException3() {
A a = new A();
verifyException(a,IllegalArgumentException.class)
.doSomethingThatThrows();
//if more details to be analized are needed
assertThat(
(IllegalStateException) caughtException(),
allOf(
is(IllegalStateException.class),
hasMessageThat(
containsString("is not allowed to add counterparties")),
hasNoCause()));
//more asserts could come
assertNotNull(a);
}
}
答案 5 :(得分:0)
如果您查看Mockito.class的间谍方法,则会使用spiedInstance创建模拟:
public static <T> T spy(T object) {
return MOCKITO_CORE.mock((Class<T>) object.getClass(), withSettings()
.spiedInstance(object)
.defaultAnswer(CALLS_REAL_METHODS));
}
在MockSettings中,可以注册调用侦听器:https://static.javadoc.io/org.mockito/mockito-core/3.0.0/org/mockito/listeners/InvocationListener.html
我创建了一个简单的侦听器,用于存储所有报告的调用:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.mockito.listeners.InvocationListener;
import org.mockito.listeners.MethodInvocationReport;
public class StoringMethodInvocationListener implements InvocationListener {
private List<MethodInvocationReport> methodInvocationReports = new ArrayList<>();
@Override
public void reportInvocation(MethodInvocationReport methodInvocationReport) {
this.methodInvocationReports.add(methodInvocationReport);
}
public List<MethodInvocationReport> getMethodInvocationReports() {
return Collections.unmodifiableList(methodInvocationReports);
}
}
调用后,您可以浏览报告并找到所需的报告,并验证存储的throwable是否为预期的报告。
示例:
StoringMethodInvocationListener listener = new StoringMethodInvocationListener();
Consumer mock2 = mock(Consumer.class, withSettings()
.spiedInstance(consumerInstance)
.defaultAnswer(CALLS_REAL_METHODS)
.invocationListeners(listener));
try {
mock2.listen(new ConsumerRecord<String, String>(RECEIVER_TOPIC, 0, 0, null, "{}"));
} catch (Exception e){
//nothing
}
Assert.notEmpty(listener.getMethodInvocationReports(), "MethodInvocationReports list must not be empty");
Assert.isInstanceOf(BindException.class, listener.getMethodInvocationReports().get(1).getThrowable());