java - 如何模拟难以实例化的类 (javax.mail.Message)?

标签 java unit-testing mocking jakarta-mail

我想在我的下一个项目中使用 junit 测试,但我不确定我应该使用几个模拟包中的哪一个。我还阅读了一些教程,但没有找到如何解决下面概述的特定问题的信息。也许该功能在我 checkout 的软件包中不可用。

这就是问题所在:我想编写一个遍历 List<javax.mail.Message> 的电子邮件过滤器类并按主题、日期、发件人、收件人等过滤电子邮件。要测试的代码如下所示:

public List<Message> doFilter(List<Message> messageList) {

    List<Message> newList = new ArrayList<Message>(messageList.size());

    try {
        for (Message message: messageList) {
            if (start != null) {
                Date sentDate = message.getSentDate();
                if (sentDate == null || sentDate.before(start))
                    continue;
            }
            if (end != null) {
                Date receivedDate = message.getReceivedDate();
                if (receivedDate == null || receivedDate.after(end))
                    continue;
            }
            newList.add(message);
        }
    }
    catch(Exception e) {
        e.printStackTrace();
    }
    return newList;
}

所以明显的测试用例是构建一个 List一些消息并检查过滤器返回的新列表是否包含正确的消息。

但是javax.mail.Message是抽象的,不能直接实例化。为此,我需要设置一个真正的电子邮件存储,包括帐户名和密码。

所以我的问题是:

  • 如何模拟一些 javax.mail.Message具有不同值的对象,以便我的过滤器类可以调用 message.getSentDate()及其他Message方法,检索我在测试设置代码中定义的值?

  • 哪些模拟包最适合解决此类问题?

非常感谢所有回答。

最佳答案

我已经尝试了两种方法来了解优缺点:

方法 1: 创建一个新的 MockMessage 类,它只实现我在过滤器代码中需要的那些方法,然后编写标准的 JUnit 测试。

缺少抽象方法的问题实际上是微不足道的,因为这些方法可以由我使用的 IDE 生成(它们将是空的,但无论如何被测代码都不需要它们)。没有实际使用 Mock 包。

public class MockMessage extends Message {

    private Date sentDate;

    public MockMessage(Date sentDate) {
        this.sentDate = sentDate;
    }

    public Date getSentDate() throws MessagingException {
        return sentDate;
    }

    // the rest of the required methods can easily be generated by the IDE
    ...
}


public void testFilter1() {

    try {
        DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd hh:mm:ss");
        final Date date0 = dtf.parseDateTime("2011-05-19 05:51:26").toDate();
        final Date date1 = dtf.parseDateTime("2011-05-19 05:51:27").toDate();
        final Date date2 = dtf.parseDateTime("2011-05-19 05:51:28").toDate();

        final List<Message> mockMessages = Arrays.asList(
            (Message)new MockMessage(date0),
            (Message)new MockMessage(date1),
            (Message)new MockMessage(date2)
        );

        MessageFilter filter = new ByDate(date1, null);
        List<Message> result = filter.doFilter(mockMessages);
        assertEquals(result.size(),2);
        assertEquals(result.get(0).getSentDate(),date1);
        assertEquals(result.get(1).getSentDate(),date2);
    }
    catch(Exception e) {
        fail(e.getMessage());
    }
}

方法 2: 使用 jMock 和 ClassImposteriser。代码量比方法 1 少一点,不需要额外的 MockMessage 类。

我仍然更喜欢第一种方法,因为它更容易理解。第二种方法在对象比 javax.mail.Message 更难实例化的其他情况下可能有用。

public void testFilter2() {

    try {
        DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd hh:mm:ss");
        final Date date0 = dtf.parseDateTime("2011-05-19 05:51:26").toDate();
        final Date date1 = dtf.parseDateTime("2011-05-19 05:51:27").toDate();
        final Date date2 = dtf.parseDateTime("2011-05-19 05:51:28").toDate();

        Mockery mockery = new Mockery();
        mockery.setImposteriser(ClassImposteriser.INSTANCE);

        final List<Message> mockMessages = Arrays.asList(
            mockery.mock(Message.class, "message 1"),
            mockery.mock(Message.class, "message 2"),
            mockery.mock(Message.class, "message 3")
        );

        mockery.checking(new Expectations() {{
           allowing(mockMessages.get(0)).getSentDate(); will(returnValue(date0));
           allowing(mockMessages.get(1)).getSentDate(); will(returnValue(date1));
           allowing(mockMessages.get(2)).getSentDate(); will(returnValue(date2));
        }});

        MessageFilter filter = new ByDate(date1, null);
        List<Message> result = filter.doFilter(mockMessages);
        assertEquals(result.size(),2);
        assertEquals(result.get(0).getSentDate(),date1);
        assertEquals(result.get(1).getSentDate(),date2);
    }
    catch(Exception e) {
        fail(e.getMessage());
    }
}

关于java - 如何模拟难以实例化的类 (javax.mail.Message)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6087738/

相关文章:

python - 如何模拟在 __init__ 中实例化的类属性?

swift - 台风以编程方式加载 Storyboard似乎可以在不阻塞的情况下执行异步实例化

java - 方法不被 mock

java - cucumber + Selenium Java : keep the browser open between test cases

java - ProcessBulder 加载进程但不启动它

c# - 使用 Moq 验证委托(delegate)

ruby - rspec 中的 double 方法有什么用?

java - 我如何模拟 java.net.URL 或以编程方式设置 spring bean 来接受构造函数参数?

java - 编写 XML 元素时设置属性的顺序

java - 如何在向 IDP 发送身份验证请求时将当前 URL 作为中继状态发送