I want to use junit tests in my next project, but I am unsure which of the several mock packages I should use. I also read through a couple of tutorials but I did not find info how to solve the specific problem outlined below. Maybe the feature is not available in the packages that I have checked out.
Here's the problem: I want to write an email filter class which iterates over a List<javax.mail.Message>
and filters the email messages by subject, date, from, to etc.The code to test looks like this:
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;
}
So the obvious test case is to construct a List
with a few messages and check whether the new list returned by the filter contains the right messages.
But javax.mail.Message
is abstract and can't be instantiated directly. I would need to set up a real email store to do that, including account name and password.
So my questions are:
How do I mock a few javax.mail.Message
objects with different values so that my filter class can call message.getSentDate()
and other Message
methods, retrieving the values that I have defined in the test setup code?
Which of the mock packages are best suited for this kind of problem?
All answers are really appreciated.
I have tried both approaches to learn about the advantages and disadvantages:
Approach 1: create a new MockMessage class that implements only those methods I need in my filter code, then write standard JUnit tests.
The problem with the missing abstract method is actually trivial, as those methods can be generated by the IDE I am using (they will be empty but they are not needed by the code under test anyway). No Mock package is actually used.
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());
}
}
Approach 2: using jMock and the ClassImposteriser. The amount of code is a bit less than in approach 1 and no extra MockMessage class is required.
I still prefer the first approach as it is simpler to understand. The second approach may be useful in other situations where objects are much more difficult to instantiate than 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());
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With