Einfacher Testen mit einem Fake-SMTP-Server

Print Friendly, PDF & Email

Das Versenden einer E-Mail ist ein wichtiger Bestandteil vieler Geschäftsprozesse. Leider ist es gar nicht so einfach, einen Service, der eine E-Mail verschickt, durch einen Unit-Test zu überprüfen. Mock-Objekte helfen zwar weiter, lassen aber offen, ob eine E-Mail wirklich versendet werden kann. Was kann man sonst tun?

Die meines Wissens beste Alternative ist, E-Mails von der Anwendung versenden zu lassen und im Unit-Test zu prüfen, ob eine E-Mail erfolgreich zugestellt worden ist. Dazu eignen sich hervorragend Fake-SMTP-Server.

Ein solcher Server ist nichts weiter als eine schlanke Bibliothek, die auf einem konfigurierbaren lokalen Port E-Mails empfängt. Zu Beginn eines Unit-Tests startet man den SMTP-Server, prüft nach dem Eintreffen der erwarteten Nachricht den Inhalt der E-Mail und fährt den Server am Ende des Unit-Tests wieder herunter. Je nach Umfang und Konfigurationsaufwand der verwendeten Bibliothek sind dazu nur wenige Zeilen Java-Code notwendig.

Hier ein Beispiel auf der Grundlage der Open-Source-Bibliothek Dumbster:

SimpleSmtpServer server = SimpleSmtpServer.start();
// Call service method
int numerOfReceivedEMails = server.getReceivedEmailSize();
SmtpMessage message = (SmtpMessage) server.getReceivedEMail().next();
String body = message.getBody();
server.stop();

Wenn man nicht nur sicherstellen will, dass eine E-Mail eingetroffen ist, sondern auch den Inhalt der E-Mail überprüfen möchte, steht man vor dem Problem, die kodierte Nachricht zu dekodieren. Eine narrensichere Lösung dazu kenne ich leider nicht. Mein derzeit bester Ansatz ist der folgende Code:

InputStream inputStream = new ReaderInputStream(new StringReader(message.getBody()));
String bodyText = IOUtils.toString(MimeUtility.decode(inputStream, "quoted-printable"));

Beim Hochfahren des SMTP-Servers trifft man schnell auf ein Problem: Der Standard-SMTP-Port (25) ist auf vielen Maschinen schon belegt bzw. lässt sich durch einen Java-Prozess ohne Root-Rechte nicht binden. Also muss man den Fake-SMTP-Server auf einem anderen Port starten und die Anwendung muss E-Mails entsprechend an diesen Port schicken. Wie stellt man aber sicher, dass ein gewählter Port immer frei ist?

Diese Frage kann glücklicherweise die Java-Laufzeitumgebung beantworten. Wenn man einen Server-Socket ohne Port-Vorgabe erzeugt, sucht die Laufzeitumgebung nach einem freien Port und bindet ihn. Wenn man nun den Server-Socket wieder schließt, kann man den zuvor gebundenen Port anschließend wiederverwenden. Hier ein Beispiel zu dieser Technik:

ServerSocket tmpSocket = new ServerSocket(0);
int freePort = tmpSocket.getLocalPort();
tmpSocket.close();
SimpleSmtpServer server = SimpleSmtpServer.start(freePort);

Zugegeben: Absolut sicher ist diese Methode der Port-Auswahl nicht, aber man kommt damit schon sehr weit.

Der Einsatz eines Fake-SMTP-Servers bietet somit eine gute Grundlage, um Tests zu schreiben, die auch den Inhalt von versendeten E-Mails einbeziehen. Indem man einen Fake-SMTP-Server als Teil eines einzelnen Unit-Tests hochfährt, benötigt man keine zusätzliche zentrale Infrastruktur und kann somit in sich geschlossene Tests schreiben.

Schreibe einen Kommentar

Fügen Sie die notwendige Nummer ins freie Feld ein *