如何使用Mockito测试sendEmail()方法而不发送电子邮件?

时间:2013-05-17 13:30:27

标签: java spring unit-testing junit mockito

我需要你帮助使用Mockito进行单元测试。 我的项目只有DAO和服务,所以它是web项目。 我有接口EmailDao和它的实现EmailDaoImpl类。现在我对EmailDaoImpl中的测试方法进行了简单的jUnit测试。这是方法sendEmail(EmailParams params),它执行诸如身份验证之类的操作,在对象EmailParams中正确设置参数,调用其他方法将电子邮件副本保存到文件系统等等。当然,还可以发送电子邮件

我的实际测试类看起来像:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/applicationContext.xml"})
@Transactional
@TransactionConfiguration(transactionManager = "txManagerTest")
public class EmailServiceTest {

    @Autowired
    private EmailDao emailDao;

    @Test
    //@Rollback(false)
    public void sendSignedEmailTest() throws Exception {

    System.out.println("-------------------------");
    System.out.println("sendSignedEmail()");
    System.out.println("-------------------------");      

    String body = "Hello, I'm evil!";

    EmailParams params = new EmailParams();
    params.setIsCourt(true);
    params.setBody(body);
    params.setFileName("test.eml");        
    params.setSaveToFile(false);
    params.setSignMessage(false);
    params.setFromAddress("xxxx@seznam.cz");
    params.setToAddresses("yyyyy@gmail.com");
    //params.setMailPriority(5);
    //params.setCcs("zzzzz@seznam.cz");
    params.setSubject("test");
    params.setUserName("aaa");

    List<Long> debtIds = new ArrayList<>();
    debtIds.add(123018L);
    //debtIds.add(184788L);
    //debtIds.add(185864L);
    params.setDebtIds(debtIds);

    DebtEvent event = new DebtEvent();
    event.setEventTypeId(5);
    event.setStatusTypeId(50);
    event.setDescription("description");
    event.setEventText("event text");
    event.setEventClientText("event client text");

    params.setSaveDebtEvent(false);
    params.setDebtEventTemplate(event);

    boolean ff = emailDao.sendEmail(params);

    System.out.println(ff);

}

现在我不想真正发送电子邮件到目标地址。所以,我拿Mockito:

@RunWith(MockitoJUnitRunner.class)
@ContextConfiguration(locations = {"classpath:/applicationContext.xml"})
@Transactional
@TransactionConfiguration(transactionManager = "txManagerTest")
public class EmailServiceTest {

    @Mock
    private EmailDao emailDao;

    @Test
    //@Rollback(false)
    public void sendSignedEmailTest() throws Exception {

    System.out.println("-------------------------");
    System.out.println("sendSignedEmail()");
    System.out.println("-------------------------");      

    String body = "Hello, I'm evil!";

    EmailParams params = new EmailParams();
    params.setIsCourt(true);
    params.setBody(body);
    params.setFileName("test.eml");        
    params.setSaveToFile(false);
    params.setSignMessage(false);
    params.setFromAddress("xxxx@seznam.cz");
    params.setToAddresses("yyyyy@gmail.com");
    //params.setMailPriority(5);
    //params.setCcs("zzzzz@seznam.cz");
    params.setSubject("test");
    params.setUserName("aaa");

    List<Long> debtIds = new ArrayList<>();
    debtIds.add(123018L);
    //debtIds.add(184788L);
    //debtIds.add(185864L);
    params.setDebtIds(debtIds);

    DebtEvent event = new DebtEvent();
    event.setEventTypeId(5);
    event.setStatusTypeId(50);
    event.setDescription("description");
    event.setEventText("event text");
    event.setEventClientText("event client text");

    params.setSaveDebtEvent(false);
    params.setDebtEventTemplate(event);

    Mockito.when(emailDao.sendEmail(params)).thenReturn(Boolean.TRUE);

    System.out.println(emailDao.sendEmail(params));

}

此代码始终返回true(没关系),但是方法sendEmail未经过测试!

你可以帮我解决这个问题吗?我不知道还有什么必须做的: - (

谢谢!

修改:// 这是EmailDaoImpl类中的sendEmail(EmailParams params):

@Override
    public boolean sendEmail(EmailParams params) throws MessagingException, EmailException {

        String from = params.getFromAddress(); 
        String to = params.getToAddresses(); 
        String ccs = params.getCcs();
        String bccs = params.getBccs();
        String subject = params.getSubject(); 
        String body = params.getBody();        
        boolean signMessage = params.isSignMessage();
        boolean saveToFile = params.isSaveToFile();
        String fileName = params.getFileName();
        boolean isCourt = params.isIsCourt();
        List<Long> debtIds = params.getDebtIds();
        String userName = params.getUserName();
        String priority = (params.getMailPriority() == null || params.getMailPriority() == 0) ? "3" : params.getMailPriority().toString();

        String message;

        // remove any last semicolon
        if (StringUtils.hasText(to)) {
            if (to.endsWith(";")) {to = to.substring(0, to.length()-1);}
            if (to.startsWith(";")) {to = to.substring(1, to.length());}            
        }

        if (StringUtils.hasText(bccs)) {
            if (bccs.endsWith(";")) {bccs = bccs.substring(0, bccs.length()-1);}
            if (bccs.startsWith(";")) {bccs = bccs.substring(1, bccs.length());}        
        }

        if (StringUtils.hasText(ccs)) {
            if (ccs.endsWith(";")) {ccs = ccs.substring(0, ccs.length()-1);}
            if (ccs.startsWith(";")) {ccs = ccs.substring(1, ccs.length());}        
        }        

        // addresses checking
        if (StringUtils.hasText(to)) {
            to = this.checkEmailAddress(to);
        }
        else {
            message = messageSource.getMessage("email.NoRecipientAddress.message", null, LocaleContextHolder.getLocale());            
            throw new EmailException(message);                                    
        }

        if (StringUtils.hasText(bccs)) {
            bccs = this.checkEmailAddress(bccs);
        }

        if (StringUtils.hasText(ccs)) {
            ccs = this.checkEmailAddress(ccs);
        }        

        // unless priority is set correctly, the end
        if (!priority.matches("[135]")) {
            message = messageSource.getMessage("email.InvalidPriorityType.message", null, LocaleContextHolder.getLocale());            
            throw new EmailException(message);            
        }        

        byte[] bytes = null;

        // I get a template events
        DebtEvent debtEventTemplate = params.getDebtEventTemplate();

        // if to store the event
        if (params.isSaveDebtEvent()) {

            // If the template is not defined, then the end
            if (debtEventTemplate == null) {
                message = messageSource.getMessage("email.InvalidDebtEventTemplate.message", null, LocaleContextHolder.getLocale());            
                throw new EmailException(message);            
            }

            // if the event does not have date, complementing the current date
            if (debtEventTemplate.getEventDate() == null) debtEventTemplate.setEventDate(Calendar.getInstance());

            // specify type of storage
            debtEventTemplate.setRepositoryId((isCourt) ? 2 : 1);     

        }        

        // create a collection of the SMTP server settings
        Properties props = System.getProperties();

        props.put("mail.smtp.host", mailHost);
        props.put("mail.smtp.port", mailPort);
        props.put("mail.transport.protocol", mailProtocol);
        props.put("mail.smtp.auth", mailAuth);        
        props.put("mail.smtps.debug", mailDebug);

        // create email session
        Session session = Session.getDefaultInstance(props, null);

        // based on session I create the unsigned MimeMessage and configure it
        MimeMessage mimeMessage = new MimeMessage(session);
        mimeMessage.setText(body);
        mimeMessage.setFrom(new InternetAddress(from));        
        mimeMessage.setRecipients(Message.RecipientType.TO, this.stringToEmailAddresses(to));
        mimeMessage.setRecipients(Message.RecipientType.CC, this.stringToEmailAddresses(ccs));
        mimeMessage.setRecipients(Message.RecipientType.BCC, this.stringToEmailAddresses(bccs));
        mimeMessage.setSubject(subject);        
        mimeMessage.setSentDate(new Date());
        mimeMessage.setHeader("X-Priority", priority);
        mimeMessage.saveChanges();

        // setup priority
        switch (priority) {

            case "1":
                mimeMessage.setHeader("X-Priority", priority);
                mimeMessage.setHeader("X-MSMail-Priority", "High");
                mimeMessage.setHeader("Importance", "High");
                break;

            case "3":
                mimeMessage.setHeader("X-Priority", priority);
                mimeMessage.setHeader("X-MSMail-Priority", "Normal");
                mimeMessage.setHeader("Importance", "Normal");
                break;

            case "5":
                mimeMessage.setHeader("X-Priority", priority);
                mimeMessage.setHeader("X-MSMail-Priority", "Low");
                mimeMessage.setHeader("Importance", "Low");
                break; 

            default:
                mimeMessage.setHeader("X-Priority", priority);
                mimeMessage.setHeader("X-MSMail-Priority", "Normal");
                mimeMessage.setHeader("Importance", "Normal");
                break;                

        }

        // If the email sign
        if (signMessage) {

            // create and configure MailcapCommandMap and MIME types used for SMIME
            final MailcapCommandMap mailcap = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
            mailcap.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature");
            mailcap.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime");
            mailcap.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature");
            mailcap.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime");
            mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed");

            CommandMap.setDefaultCommandMap(mailcap);            

            // sign message
            MimeMultipart mm = null;

            try {
                mm = signMessage(mimeMessage);
            } catch (KeyStoreException ex) {
                Logger.getLogger(EmailDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(EmailDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
            } catch (NoSuchAlgorithmException ex) {
                Logger.getLogger(EmailDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
            } catch (CertificateException ex) {
                Logger.getLogger(EmailDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
            } catch (UnrecoverableKeyException ex) {
                Logger.getLogger(EmailDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InvalidAlgorithmParameterException ex) {
                Logger.getLogger(EmailDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
            } catch (NoSuchProviderException ex) {
                Logger.getLogger(EmailDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
            } catch (CertStoreException ex) {
                Logger.getLogger(EmailDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SMIMEException ex) {
                Logger.getLogger(EmailDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
            } catch (Exception ex) {
                Logger.getLogger(EmailDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
            }

            // Copied headers from the original unsigned messages to new message
            final Enumeration headers = mimeMessage.getAllHeaderLines();

            // create a new envelope
            mimeMessage = new MimeMessage(session);

            while (headers.hasMoreElements()){
                mimeMessage.addHeaderLine((String)headers.nextElement());
            }

            // I put the signed content
            mimeMessage.setContent(mm);
            mimeMessage.saveChanges();

        }     

        // If email have to save to file
        if (saveToFile) {

            // too many lines of code 

        }              

        // send email
        Transport.send(mimeMessage);        

        // return true
        return true;

    }

3 个答案:

答案 0 :(得分:1)

emailDao sendEmail方法应该在单独的测试中测试(测试dao)。

在该测试中,您应该模拟emailService(仅负责与Web服务器通信的部分)。

你不应该测试同一个测试类中的所有东西,因为它太复杂了。

如果您想检查传递给sendEmail方法的参数,可以使用thenAnswer代替thenReturn。在Mockito中阅读有关answers的更多信息。

答案 1 :(得分:0)

首先,你没有断言。如果您没有断言,则不进行测试。 其次,由于您的DAO正在执行保存和邮件发送,这意味着它实际上并不是DAO。称之为服务或其他什么。

关于你的问题,你得到了真实,因为你要求mockito这样做。

当你测试一个单元时,这意味着你给它固定的输入,期望一个特定的输出,并模拟所有的依赖。你不要模拟你测试的类。

邮件发送本身应由另一个组件处理;那是你应该嘲笑的那个。

答案 2 :(得分:-1)

如果你想测试一个类(及其方法),你不应该嘲笑它!实际上,mock是接口或类的虚拟实现。它通常用于模拟对其他类的方法的调用(并且不要担心依赖关系,并专注于测试类)。

祝你好运