[英]Mockito doThrow on void method with null argument not throwing exception: What am I doing wrong?
I am unsure if I have found a bug or if I am just doing it wrong.我不确定我是否发现了错误,或者我是否只是做错了。 I am trying to have a mock throw an exception when a method is invoked (relatively easy normally), except the method is of
void
return type, and the object to be passed in (why the error is thrown) is null
.我试图在调用方法时模拟抛出异常(通常相对容易),除了该方法是
void
返回类型,并且要传入的对象(为什么会抛出错误)为null
。 This can be typed through isNull()
to compile, but the error is still not thrown.这个可以通过
isNull()
输入编译,但是还是不抛出错误。
package some.example;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.MockitoAnnotations.initMocks;
import javax.jms.Message;
import javax.jms.MessageListener;
import org.mockito.Mock;
import org.springframework.jms.listener.AbstractMessageListenerContainer;
import org.springframework.jms.listener.SessionAwareMessageListener;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class TestClass {
@Mock
private AbstractMessageListenerContainer messageContainer;
@BeforeClass
public void setUpMocks() {
initMocks(this);
doThrow(new IllegalArgumentException()).when(messageContainer).setupMessageListener(
isNull(MessageListener.class));
doThrow(new IllegalArgumentException()).when(messageContainer).setupMessageListener(
isNull(SessionAwareMessageListener.class));
}
@AfterMethod
public void resetMocks() {
reset(messageContainer);
}
@Test(expectedExceptions = { IllegalArgumentException.class })
public void testSetUpQueueConsumerWithNullMessageListener() throws Exception {
final MessageListener messageListener = null;
try (final QueueConsumer consumer = new QueueConsumer(messageContainer, messageListener)) {
} finally {
verify(messageContainer).setupMessageListener(messageListener);
}
}
@Test(expectedExceptions = { IllegalArgumentException.class })
public void testSetUpQueueConsumerWithNullSessionAwareMessageListener() throws Exception {
final SessionAwareMessageListener<Message> messageListener = null;
try (final QueueConsumer consumer = new QueueConsumer(messageContainer, messageListener)) {
} finally {
verify(messageContainer).setupMessageListener(messageListener);
}
}
public class QueueConsumer implements AutoCloseable {
private final AbstractMessageListenerContainer messageContainer;
QueueConsumer(final AbstractMessageListenerContainer messageContainer,
final SessionAwareMessageListener<? extends Message> messageListener) {
this(messageContainer);
this.messageContainer.setupMessageListener(messageListener);
}
QueueConsumer(final AbstractMessageListenerContainer messageContainer, final MessageListener messageListener) {
this(messageContainer);
this.messageContainer.setupMessageListener(messageListener);
}
private QueueConsumer(final AbstractMessageListenerContainer messageContainer) {
if (messageContainer == null) {
throw new IllegalArgumentException("MessageListenerContainer cannot be null");
}
this.messageContainer = messageContainer;
}
public void stop() {
messageContainer.stop();
}
@Override
public void close() throws Exception {
stop();
}
}
}
Relevant maven dependencies:相关的maven依赖:
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.8.21</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.0.8-beta</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${org.springframework.version}</version>
</dependency>
EDIT编辑
I added the stripped down real code.我添加了精简的真实代码。 I toyed with the code more this morning, and discovered I was using Mockito's
reset()
incorrectly.今天早上我更多地玩弄代码,发现我错误地使用了 Mockito 的
reset()
。 I thought it would reset the mock to its unverified state, but it also erases the doThrow()
stubs.我认为它会将模拟重置为其未验证状态,但它也会删除
doThrow()
存根。 I had to change the initialization methods as follows:我不得不改变初始化方法如下:
@BeforeClass
public void setUpMocks() {
initMocks(this);
}
@BeforeMethod
public void setUpThrows() {
doThrow(new IllegalArgumentException()).when(messageContainer).setupMessageListener(
isNull(MessageListener.class));
doThrow(new IllegalArgumentException()).when(messageContainer).setupMessageListener(
isNull(SessionAwareMessageListener.class));
}
As resolved in the comments and edit: Be careful to note that the reset
method resets the mock entirely , including both stubs and interactions (the latter for verifications).如评论和编辑中所解决:请注意
reset
方法完全重置模拟,包括存根和交互(后者用于验证)。
As warned in the Mockito documentation , reset
is generally a bad sign in your tests: If it comes in the middle of a test method, generally that method should be split up into multiple smaller tests, and if it comes in an @After
or @AfterMethod
it means that your test setup is polluting between tests.正如Mockito 文档中所警告的那样,
reset
在您的测试中通常是一个不好的迹象:如果它出现在测试方法的中间,通常该方法应该被分成多个较小的测试,如果它出现在@After
或@AfterMethod
这意味着您的测试设置在测试之间存在污染。 Keep your mocks in instance fields, not static fields, initialized in a @Before
(JUnit) or @BeforeMethod
(TestNG) method to ensure they're fully overwritten before every single test in a test class.将您的
@Before
保持在实例字段中,而不是静态字段中,在@Before
(JUnit) 或@BeforeMethod
(TestNG) 方法中初始化,以确保它们在测试类中的每个单独测试之前被完全覆盖。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.