Javamail smells, we need a better Java mail library

When one starts using Javamail library, the inevitable problem will arise. Unit-testing.

Testing Javamail-related functionality can be a major pain. You want to test how your messages are created, what contents and headers they have, whom they are addressed to, when they are sent etc., and this is where the problems start.

Personally, I don't understand why I have to have a Session initialized and passed as a constructor parameter when I have to create a MimeMessage instance. Why on Earth do I need this Session to be created, especially in test environment? What point does it serve?

I am not going to send out any actual messages. I want to mock mail sending functionality, but this is a surprisingly complex thing to do. The Session class is marked final and you cannot easily subclass or mock it, you have to use advanced mocking frameworks such as Powermock. I don't like to use Powermock unless it is completely necessary - it has a drawback of depending on a custom Junit runner and I may already have another custom runner in place. Also, you may have to provide stubs for some of the Session methods. It seems to me like another waste of time and code: after all, all I want to do is to build a message and then test how well it is build, not stub some methods I don't even care about.

There is another, simpler way: you can leave the Session intact and create mock classes for Transports, Folder, messages' Store etc., and make Javamail use them in the test environment, instead of real ones. You can read how to do it here or you can use the ready Mock-Javamail library.

This techique effectively allows you create an in-memory mail server so that you can "send" message in your main code and "receive" them in your test code. It still doesn't feel right to me. It breaks "convention-over-configuration" concept (you have to do additional configuration so your mock objects can be used). Moreover, the tests' isolation suffers - if you run multiple tests simultaneously, you cannot verify which one of them actually created that message in your virtual mailbox!

Spring mail functionality (namely, the JavaMailSenderImpl class) can save your day: its createMimeMessage() method is easily stubbed and then you can mock and verify everything mail-ish. The SimpleMailMessage is an even better solution when you don't need advanced MimeMessage functionality - it is really simple to use and to test. But it will make you vendor-dependent so it doesn't work for everyone.

The final point is: problems with Javamail testing indicate a serious code smell. Unfortunately, all we can really do about it is hope things get better in future. But if you're okay with being vendor-dependent, then Spring mail functionality can simplify your testing.

Comments

Popular posts from this blog

Multi-threading skills - what do you mean by that?

Code reviews, recommended reading

Spring Framework and Code Obscurity