Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/398.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 无法使用mockito对此方法中引发的异常进行单元测试_Java_Unit Testing_Junit_Mockito - Fatal编程技术网

Java 无法使用mockito对此方法中引发的异常进行单元测试

Java 无法使用mockito对此方法中引发的异常进行单元测试,java,unit-testing,junit,mockito,Java,Unit Testing,Junit,Mockito,我已经使用mockito编写了以下单元测试来测试我的EmailService.java类。我不确定的是,我是否正确地测试了它(快乐路径和异常场景) 此外,我得到了这个错误:此处不允许使用“void”类型 在我的单元测试中的以下代码段中 when(mockEmailService.notify(anyString())).thenThrow(MailException.class); 我知道,由于我的notify()方法返回void,我得到了该异常。但不知道如何解决这个问题。在我的单元测试或实际

我已经使用
mockito
编写了以下单元测试来测试我的
EmailService.java
类。我不确定的是,我是否正确地测试了它(快乐路径和异常场景)

此外,我得到了这个
错误:此处不允许使用“void”类型
在我的单元测试中的以下代码段中

when(mockEmailService.notify(anyString())).thenThrow(MailException.class);
我知道,由于我的
notify()
方法返回void,我得到了该异常。但不知道如何解决这个问题。在我的单元测试或实际类或两者中是否需要任何代码更改

有人能给我引路吗

EmailServiceTest.java

public class EmailServiceTest {

    @Rule
    public MockitoJUnitRule rule = new MockitoJUnitRule(this);

    @Mock
    private MailSender mailSender;
    @Mock
    private EmailService mockEmailService;
    private String emailRecipientAddress = "recipient@abc.com";
    private String emailSenderAddress = "sender@abc.com";
    private String messageBody = "Hello Message Body!!!";

    @Test
    public void testNotify() {
        EmailService emailService = new EmailService(mailSender, emailRecipientAddress, emailSenderAddress);
        emailService.notify(messageBody);
    }

    @Test(expected = MailException.class)
    public void testNotifyMailException() {
        when(mockEmailService.notify(anyString())).thenThrow(MailException.class);
        EmailService emailService = new EmailService(mailSender, emailRecipientAddress, emailSenderAddress);
        emailService.notify(messageBody);
    }

}
public class EmailService {
    private static final Log LOG = LogFactory.getLog(EmailService.class);
    private static final String EMAIL_SUBJECT = ":: Risk Assessment Job Summary Results::";
    private final MailSender mailSender;
    private final String emailRecipientAddress;
    private final String emailSenderAddress;

    public EmailService(MailSender mailSender, String emailRecipientAddress,
            String emailSenderAddress) {
        this.mailSender = mailSender;
        this.emailRecipientAddress = emailRecipientAddress;
        this.emailSenderAddress = emailSenderAddress;
    }

    public void notify(String messageBody) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setSubject(EMAIL_SUBJECT);
        message.setTo(emailRecipientAddress);
        message.setFrom(emailSenderAddress);
        message.setText(messageBody);
        try {
            mailSender.send(message);
        } catch (MailException e) {
            LOG.error("Error while sending notification email: ", e);
        }
    }
}
public class EmailServiceTest {

    @Rule
    public MockitoJUnitRule rule = new MockitoJUnitRule(this);

    @Mock
    private MailSender mailSender;
    private String emailRecipientAddress = "recipient@abc.com";
    private String emailSenderAddress = "sender@abc.com";
    private String messageBody = "Hello Message Body!!!";
    @Mock
    private EmailService mockEmailService;

    @Test
    public void testNotify() {
        EmailService EmailService = new EmailService(mailSender, emailRecipientAddress, emailSenderAddress);
        EmailService.notify(messageBody);
    }

    @Test(expected = KlarnaEmailSendException.class)
    public void testNotifyMailException() {
        doThrow(new KlarnaEmailSendException("Some error message")).when(mockKlarnaEmailService).notify(anyString());
        mockKlarnaEmailService.notify(messageBody);
    }
}
EmailService.java

public class EmailServiceTest {

    @Rule
    public MockitoJUnitRule rule = new MockitoJUnitRule(this);

    @Mock
    private MailSender mailSender;
    @Mock
    private EmailService mockEmailService;
    private String emailRecipientAddress = "recipient@abc.com";
    private String emailSenderAddress = "sender@abc.com";
    private String messageBody = "Hello Message Body!!!";

    @Test
    public void testNotify() {
        EmailService emailService = new EmailService(mailSender, emailRecipientAddress, emailSenderAddress);
        emailService.notify(messageBody);
    }

    @Test(expected = MailException.class)
    public void testNotifyMailException() {
        when(mockEmailService.notify(anyString())).thenThrow(MailException.class);
        EmailService emailService = new EmailService(mailSender, emailRecipientAddress, emailSenderAddress);
        emailService.notify(messageBody);
    }

}
public class EmailService {
    private static final Log LOG = LogFactory.getLog(EmailService.class);
    private static final String EMAIL_SUBJECT = ":: Risk Assessment Job Summary Results::";
    private final MailSender mailSender;
    private final String emailRecipientAddress;
    private final String emailSenderAddress;

    public EmailService(MailSender mailSender, String emailRecipientAddress,
            String emailSenderAddress) {
        this.mailSender = mailSender;
        this.emailRecipientAddress = emailRecipientAddress;
        this.emailSenderAddress = emailSenderAddress;
    }

    public void notify(String messageBody) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setSubject(EMAIL_SUBJECT);
        message.setTo(emailRecipientAddress);
        message.setFrom(emailSenderAddress);
        message.setText(messageBody);
        try {
            mailSender.send(message);
        } catch (MailException e) {
            LOG.error("Error while sending notification email: ", e);
        }
    }
}
public class EmailServiceTest {

    @Rule
    public MockitoJUnitRule rule = new MockitoJUnitRule(this);

    @Mock
    private MailSender mailSender;
    private String emailRecipientAddress = "recipient@abc.com";
    private String emailSenderAddress = "sender@abc.com";
    private String messageBody = "Hello Message Body!!!";
    @Mock
    private EmailService mockEmailService;

    @Test
    public void testNotify() {
        EmailService EmailService = new EmailService(mailSender, emailRecipientAddress, emailSenderAddress);
        EmailService.notify(messageBody);
    }

    @Test(expected = KlarnaEmailSendException.class)
    public void testNotifyMailException() {
        doThrow(new KlarnaEmailSendException("Some error message")).when(mockKlarnaEmailService).notify(anyString());
        mockKlarnaEmailService.notify(messageBody);
    }
}

不幸的是,问题中给出的代码存在许多问题。例如:指示测试抛出一个异常。并期望该异常在测试中得到弥补

但是:

您的生产代码正在捕获异常。因此,您编写了一个测试,只有在生产代码不正确时才能通过

现在,如果测试是错误的:您可以研究模拟记录器对象;验证是否发生了对它的调用。您可以将测试用例更改为而不是期望出现任何异常。这就是try/catch的全部要点;不是吗

或者反过来说:如果你不想抓住它;单元测试告诉您,尝试/捕获必须停止

如前所述,这只是这里的一个问题——其他答案很好地列出了它们

从这个角度来看,答案可能是:不要试图通过反复试验来学习单元测试。取而代之的是:找一本好书或教程,学习如何进行单元测试——包括如何正确使用模拟框架

1)关于如何模拟
void
方法的文档,例外情况如下:

在您的情况下,应该是这样的:

doThrow(new MailException()).when(mockEmailService).notify( anyString() );
2) 您的
testNotify
没有进行正确的测试。调用actual
notify
后,方法不检查预期结果


3) 您的
testNotifyMailException
首先模拟
notify
,然后在非模拟的EmailService上调用实际的
notify
方法模拟
notify
的全部目的是测试调用它的代码,而不是实际模拟的方法。

您不应该真正模拟您试图测试的类。我认为您真正想要做的是模拟MailSender抛出异常。我注意到您已经在成功的测试中使用了模拟邮件发送者。只需再次使用此选项并设定期望值:

 when(mailSender.send(any(SimpleMailMessage.class))).thenThrow(MailException.class);
public class EmailServiceTest {

    @Rule
    public MockitoJUnitRule rule = new MockitoJUnitRule(this);

    @Mock
    private MailSender mailSender;
    private String emailRecipientAddress = "recipient@abc.com";
    private String emailSenderAddress = "sender@abc.com";
    private String messageBody = "Hello Message Body!!!";
    @Mock
    private EmailService mockEmailService;

    @Test
    public void testNotify() {
        EmailService EmailService = new EmailService(mailSender, emailRecipientAddress, emailSenderAddress);
        EmailService.notify(messageBody);
    }

    @Test(expected = KlarnaEmailSendException.class)
    public void testNotifyMailException() {
        doThrow(new KlarnaEmailSendException("Some error message")).when(mockKlarnaEmailService).notify(anyString());
        mockKlarnaEmailService.notify(messageBody);
    }
}

但是正如@GhostCat的回答中提到的,您正在方法中进行异常处理,因此您需要指定一个不同的期望值,而不是要抛出的异常。您可以模拟记录器,但模拟静态记录器通常需要付出更多的努力。您可能需要考虑重新处理异常处理以便于测试。

< P>基于上述响应,我通过修改实际的类和单元测试来工作。 EmailSendException.java(添加新类以提高可测试性)

public class EmailServiceTest {

    @Rule
    public MockitoJUnitRule rule = new MockitoJUnitRule(this);

    @Mock
    private MailSender mailSender;
    private String emailRecipientAddress = "recipient@abc.com";
    private String emailSenderAddress = "sender@abc.com";
    private String messageBody = "Hello Message Body!!!";
    @Mock
    private EmailService mockEmailService;

    @Test
    public void testNotify() {
        EmailService EmailService = new EmailService(mailSender, emailRecipientAddress, emailSenderAddress);
        EmailService.notify(messageBody);
    }

    @Test(expected = KlarnaEmailSendException.class)
    public void testNotifyMailException() {
        doThrow(new KlarnaEmailSendException("Some error message")).when(mockKlarnaEmailService).notify(anyString());
        mockKlarnaEmailService.notify(messageBody);
    }
}
EmailService.java(不是捕获,而是抛出RuntimeException)

public class EmailServiceTest {

    @Rule
    public MockitoJUnitRule rule = new MockitoJUnitRule(this);

    @Mock
    private MailSender mailSender;
    private String emailRecipientAddress = "recipient@abc.com";
    private String emailSenderAddress = "sender@abc.com";
    private String messageBody = "Hello Message Body!!!";
    @Mock
    private EmailService mockEmailService;

    @Test
    public void testNotify() {
        EmailService EmailService = new EmailService(mailSender, emailRecipientAddress, emailSenderAddress);
        EmailService.notify(messageBody);
    }

    @Test(expected = KlarnaEmailSendException.class)
    public void testNotifyMailException() {
        doThrow(new KlarnaEmailSendException("Some error message")).when(mockKlarnaEmailService).notify(anyString());
        mockKlarnaEmailService.notify(messageBody);
    }
}
EmailServiceTest.java(模拟和测试)

public class EmailServiceTest {

    @Rule
    public MockitoJUnitRule rule = new MockitoJUnitRule(this);

    @Mock
    private MailSender mailSender;
    private String emailRecipientAddress = "recipient@abc.com";
    private String emailSenderAddress = "sender@abc.com";
    private String messageBody = "Hello Message Body!!!";
    @Mock
    private EmailService mockEmailService;

    @Test
    public void testNotify() {
        EmailService EmailService = new EmailService(mailSender, emailRecipientAddress, emailSenderAddress);
        EmailService.notify(messageBody);
    }

    @Test(expected = KlarnaEmailSendException.class)
    public void testNotifyMailException() {
        doThrow(new KlarnaEmailSendException("Some error message")).when(mockKlarnaEmailService).notify(anyString());
        mockKlarnaEmailService.notify(messageBody);
    }
}

我将假设这里的
EmailService
实现是正确的,并将重点放在测试上。他们都有缺陷。虽然
testNotify
执行时没有错误,但它实际上并没有测试任何东西。从技术上讲,当
mailService
没有引发异常时,它至少会确认
notify
没有引发异常。我们可以做得更好

编写好测试的关键是问自己,“这个方法应该做什么?”你应该能够在编写方法之前回答这个问题。对于特定的测试,请询问“它应该如何处理此输入?”或“当其依赖项执行此操作时,它应该如何处理?”

在第一种情况下,创建一个
MailService
,向其传递
mailssender
和发送地址。调用
MailService
实例的
notify
方法时,该实例应该做什么?它应该通过
send
方法将
simpleEmailMessage
传递给
mailssender
。下面是如何做到这一点的(注意,我假设
mailssender
实际上使用
MailMessage
接口,而不是
SimpleMailMessage
):

或者,我们可以捕获
邮件异常
,然后显式地使测试失败:

@Test
public void testMailExceptionAlternate() {
    try {
        Mockito.doThrow(Mockito.mock(MailException.class)).when(mailSender).send(Mockito.any(MailMessage.class));
        emailService.notify(messageBody);
    } catch (MailException ex){
        Assert.fail("MailException was supposed to be caught.");
    }
}
这两种方法都确认了所需的行为。第二个问题在测试内容上更为明确。不过,缺点是,如果在其他情况下允许
notify
抛出
mailseption
,那么该测试可能不起作用


最后,如果
maileexception
是一个已检查的异常,即它不是
RuntimeException
,那么您甚至不需要测试它。如果
notify
可能抛出
MailException
,那么编译器将要求它在方法签名中声明它。

抱歉,复制粘贴问题。修正了你的单元测试失败了吗?你收到了什么错误信息?第一条正在通过,第二条没有通过。根据mockito,语法不正确。不确定我的生产代码是否需要返工或单元测试。请试一试。获取异常
org.springframework.mail.MailException是抽象的;无法实例化
尝试使用具体的扩展类,如
MailSendException
。真的吗?这似乎很奇怪,您能粘贴新的testNotifyMailException()方法吗?
@Test(预期=MailException.class)public void testNotifyMailException(){when(mailSender.s