かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Spring Boot でメール送信する Web アプリケーションを作る ( その11 )( メール送信画面の作成5 )

概要

Spring Boot でメール送信する Web アプリケーションを作る ( その10 )( DataSource Bean の独自定義は不要?他 ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • メール送信画面の作成
    • 今回はテストクラスを書きます。長いので2回に分けます。
    • Java のメール送信の unit test 用ライブラリ Wiser、GreenMail を試してみます。

ソフトウェア一覧

参考にしたサイト

  1. A SMTP server in Java for unit test
    http://www.javatronic.fr/articles/2014/02/15/a_smtp_server_in_java_for_unit_test.html

  2. Working with a Java Mail Server for Testing
    http://stackoverflow.com/questions/2782546/working-with-a-java-mail-server-for-testing?s=1|1.8801

  3. SubEthaMailのwiserで仮想SMTPを立ててjavaのメール送信をユニットテストする!
    http://treeapps.hatenablog.com/entry/2015/01/10/012647

  4. SubEtha SMTP
    https://github.com/voodoodyne/subethasmtp

  5. GreenMail
    http://www.icegreen.com/greenmail/

  6. this.getClass().getClassLoader().getResource(“…”) and NullPointerException
    http://stackoverflow.com/questions/3803326/this-getclass-getclassloader-getresource-and-nullpointerexception

    • テストデータの YAML ファイルをテストクラスとは別の場所に配置した時に getClass().getResourceAsStream(...) でどう指定すればよいのか分からなかった時に参考にしました。

手順

unit test 用のメールサーバのライブラリとして何を使用するか?

  • いろいろありますが ( GreenMailの「Related projects to JavaMail and testing/development:」と書かれたところに主なライブラリの一覧が書かれています ) 、使用例の記事が多いと思われたのは Wiser と GreenMail でした。
  • Wiser はメールの送信と送信したメールの内容の確認の機能のみですが、安定していて軽快そうな印象があります。
  • GreenMail は SMTP 以外に POP3IMAP もサポートされており、機能が豊富でホームページも綺麗にまとまっている印象です。
  • どちらも試してみたいと思います。

テスト作成対象のクラス

今回は以下のクラスのテストクラスを作成します。

  • util/VelocityUtils
  • helper/mail/MAIL001MailHelper
  • service/EmailService

次回、以下のクラスのテストクラスを作成します。

  • web/mailsend/MailsendService
  • web/mailsend/MailsendController

ブランチの作成

  1. IntelliJ IDEA で 1.0.x-maketest-mailsend ブランチを作成します。

JUnit の設定

JUnit の設定を忘れていたので設定します。

  1. メインメニューから「Run」-「Edit Configurations...」を選択します。

  2. 「Run/Debug Configuraitons」ダイアログが表示されます。左側のツリーで「Defaults」-「JUnit」を選択した後、右側の画面の「VM options」の末尾に -Dspring.profiles.active=unittest -Dfile.encoding=UTF-8 を追加します。追加後「OK」ボタンをクリックしてダイアログを閉じます。

    f:id:ksby:20150514020221p:plain

※あとで Spring Boot でメール送信する Web アプリケーションを作る ( その3 )( Project の作成 ) にこの手順を追加しておきます。

util/VelocityUtils のテストクラスの作成

  1. テスト用の Velocity テンプレートファイルを作成します。src/test/resources の下に ksbysample/webapp/email/util ディレクトリを作成します。

  2. src/test/resources/ksbysample/webapp/email/util の下に VelocityUtilsTest.vm を新規作成します。作成後、リンク先の内容 に変更します。

  3. src/main/java/ksbysample/webapp/email/util の下の VelocityUtils.java を開いた後、クラス名にカーソルを移動して Alt+Enter を押します。コンテキストメニューが表示されたら「Create Test」を選択します。

    f:id:ksby:20150514021953p:plain

  4. 「Create Test」ダイアログが表示されます。画面上部の「Testing library」で「JUnit4」を選択し、画面下部のメソッド一覧からテスト対象のメソッドをチェックした後「OK」ボタンをクリックします。

    f:id:ksby:20150514022158p:plain

  5. src/test/java/ksbysample/webapp/email/util の下に VelocityUtilsTest.java が生成されます。リンク先の内容 に変更します。

  6. テストを実行します。VelocityUtilsTest.java の testMerge メソッドにカーソルを移動した後、コンテキストメニューを表示して「Run 'testMerge()' with Coverage」メニューを選択します。

    f:id:ksby:20150515004343p:plain

    テストが実行されて「All Test Passed」の文字が表示されます。

    f:id:ksby:20150515004540p:plain

helper/mail/MAIL001MailHelper のテストクラスの作成

  1. テストで使用する MailsendForm クラスのテストデータを作成します。src/test/resources/ksbysample/webapp/email の下に web/mailsend ディレクトリを作成します。

  2. src/test/resources/ksbysample/webapp/email/web/mailsend の下に mailsendForm_simple.yml, mailsendForm_minimum.yml を新規作成します。作成後、リンク先の内容 に変更します。

  3. src/main/java/ksbysample/webapp/email/helper/mail の MAIL001MailHelper.java から MAIL001MailHelperTest.java を生成します。

  4. src/test/java/ksbysample/webapp/email/helper/mail の下の MAIL001MailHelperTest.javaリンク先の内容 に変更します。

  5. テストを実行します。MAIL001MailHelperTest.java のクラス名にカーソルを移動した後、コンテキストメニューを表示して「Run 'MAIL001MailHelperTest' with Coverage」メニューを選択します。

    テストが実行されますが、「MailsendFormの必須項目のみ値がセットされている場合」のテストが失敗しました。

    f:id:ksby:20150515021811p:plain

    原因は MAIL001MailHelper クラスの generateTextUsingVelocity メソッドで getItem() で取得したリストを Null チェックをせずに Stream API で処理していたため、NullPointerException が発生していたためでした。

  6. src/main/java/ksbysample/webapp/email/helper/mail の下の MAIL001MailHelper.javaリンク先の内容 に変更します。

  7. 再度 MAIL001MailHelperTest.java のクラス名から「Run 'MAIL001MailHelperTest' with Coverage」メニューを選択します。今度はテストが正常に終了して「All Test Passed」の文字が表示されました。

    f:id:ksby:20150516001724p:plain

Wiser 用 ExternalResource 継承クラス、service/EmailService のテストクラスの作成

  1. build.gradle を リンク先の内容 に変更します。

  2. Gradle projects View の左上にある「Refresh all Gradle projects」アイコンをクリックして、変更した build.gradle の内容を反映します。

  3. src/test/java/ksbysample/webapp/email の下に test パッケージを作成します。

  4. src/test/java/ksbysample/webapp/email/test の下に MailServerWiserResource.java を新規作成します。作成後、リンク先の内容 に変更します。

  5. src/main/java/ksbysample/webapp/email/service の EmailService.java から EmailServiceTest.java を生成します。

  6. src/test/java/ksbysample/webapp/email/service の下の EmailServiceTest.javaリンク先のその1の内容 に変更します。

  7. テストを実行します。もしこの時点で smtp4dev が起動している場合には終了して下さい。起動していると ポート番号 25 が使用されてしまうため、Wiser が起動しません。

  8. EmailServiceTest.java 内のクラス名「Wiserを利用してメール送信する場合」にカーソルを移動した後、コンテキストメニューを表示して「Run 'MAIL001MailHelperTest' with Coverage」メニューを選択します。

    テストが実行されて「All Test Passed」の文字が表示されます。

    f:id:ksby:20150516092948p:plain

GreenMail 用 service/EmailService のテストクラスの作成

  1. GreenMail は Rule ( ExternalResource 継承クラス ) が用意されています。そのまま利用してみます。

  2. src/test/java/ksbysample/webapp/email/service の下の EmailServiceTest.javaリンク先のその2の内容 に変更します。

  3. テストを実行します。EmailServiceTest.java 内のクラス名「GreenMailを利用してメール送信する場合」にカーソルを移動した後、コンテキストメニューを表示して「Run 'MAIL001MailHelperTest' with Coverage」メニューを選択します。

    テストが実行されて「All Test Passed」の文字が表示されます。

    f:id:ksby:20150516093210p:plain

Wiser と GreenMail のどちらを使用するか?

  • 1通メールを送信するだけならば、どちらも使い勝手、性能は変わりませんでした。
  • 大量のメール送信や、添付ファイル付きメールの送信では変わるのかもしれませんが、現時点では検証していないので何とも言えません。
  • POP3IMAP の試験をすることはまずないので、Wiser でも全然問題がありません。
  • GreenMail はあらかじめライブラリで Rule 用のクラスが用意されており、別途用意する必要がない点は便利です。
  • stackoverflow で、GreenMail で問題が発生したので SubEthaSmtp/Wiser へ切り替えたという回答を書いている人がいたので、その点はちょっと気になります。
  • jcenter やそれぞれのライブラリのホームページを見てみると、Wiser は2年前くらいで更新が止まっていますが、GreenMail は 2015/4/27 にバージョン 1.4.1 がリリースされています。GreenMail は専用ホームページも綺麗にまとまっている印象があります。
  • 以下の方針で進めることにします。
    • 性能の違いがあるようなら Wiser かなと考えていたのですが、現時点では差異は見られず、機能の豊富さやホームページのまとまり具合から GreenMail を使用したいと思います。
    • ただし Rule ( ExternalResource 継承クラス ) は GreenMail のものをそのまま使用せず、別途作成します。問題が発生するようならば ExternalResource 継承クラスを変更するだけで Wiser 等の別のライブラリに切り替えることができるようにしておきます。

メールサーバ用 ExternalResource 継承クラス ( GreenMail 使用版 ) の作成

  1. src/test/java/ksbysample/webapp/email/test の下に MailServerResource.java を新規作成します。作成後、リンク先の内容 に変更します。

  2. src/test/java/ksbysample/webapp/email/service の下の EmailServiceTest.javaリンク先のその3の内容 に変更します。

    • Wiser と GreenMail のテストクラスはそのまま残しておきます。
    • MailServerResource を使用したテストクラスを追加します。
    • テストクラス内の全てのネストしたクラスをテストしようと思ったところ、テスト出来ない ( 「Run ... with Coverage」のメニューが表示されない ) ことに気づきました。EmailServiceTest クラスに @RunWith(Enclosed.class) を追加して出来るようにします。
  3. 今回はテストクラス内の全てのテストを実行してみます。EmailServiceTest.java のクラス名にカーソルを移動した後、コンテキストメニューを表示して「Run 'EmailServiceTest' with Coverage」メニューを選択します。

    f:id:ksby:20150516214529p:plain

    全てのテストが実行されて「All Test Passed」の文字が表示されます。

    f:id:ksby:20150516222851p:plain

次回は。。。

テストクラスの作成の続きです。web/mailsend/MailsendService のテストクラスを作成しているのですが、時間がかかっているので途中で区切ることにしました。commit 等は次回実施します。

ソースコード

VelocityUtilsTest.vm

テスト: $testdata

VelocityUtilsTest.java

package ksbysample.webapp.email.util;

import ksbysample.webapp.email.Application;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import java.util.HashMap;
import java.util.Map;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class VelocityUtilsTest {

    private final String templateLocation = "ksbysample/webapp/email/util/VelocityUtilsTest.vm";

    @Autowired
    private VelocityUtils velocityUtils;

    @Test
    public void testMerge() throws Exception {
        Map<String, Object> model = new HashMap<>();
        model.put("testdata", "VelocityUtils のテストです。");
        String testString = velocityUtils.merge(templateLocation, model);
        assertThat(testString, is("テスト: VelocityUtils のテストです。"));
    }
}

mailsendForm_simple.yml, mailsendForm_minimum.yml

■mailsendForm_simple.yml

!!ksbysample.webapp.email.web.mailsend.MailsendForm
fromAddr: test@sample.com
toAddr: xxx@yyy.zzz
subject: テスト
name: 田中 太郎
sex: 1
type: 1
item:
  - 101
  - 102
  - 103
naiyo: これはテストです。

■mailsendForm_minimum.yml

!!ksbysample.webapp.email.web.mailsend.MailsendForm
fromAddr: test@sample.com
toAddr: xxx@yyy.zzz
subject: テスト
name:
sex:
type:
item:
naiyo:

MAIL001MailHelperTest.java

package ksbysample.webapp.email.helper.mail;

import ksbysample.webapp.email.Application;
import ksbysample.webapp.email.web.mailsend.MailsendForm;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.yaml.snakeyaml.Yaml;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class MAIL001MailHelperTest {

    private final MailsendForm mailsendFormSimple
            = (MailsendForm) new Yaml().load(getClass().getResourceAsStream("/ksbysample/webapp/email/web/mailsend/mailsendForm_simple.yml"));
    private final MailsendForm mailsendFormMinimum
            = (MailsendForm) new Yaml().load(getClass().getResourceAsStream("/ksbysample/webapp/email/web/mailsend/mailsendForm_minimum.yml"));

    @Autowired
    private MAIL001MailHelper mail001MailHelper;

    @Test
    public void MailsendFormの全てに値がセットされている場合() throws Exception {
        SimpleMailMessage message = mail001MailHelper.createMessage(mailsendFormSimple);
        assertThat(message.getFrom(), is(mailsendFormSimple.getFromAddr()));
    }

    @Test
    public void MailsendFormの必須項目のみ値がセットされている場合() throws Exception {
        SimpleMailMessage message = mail001MailHelper.createMessage(mailsendFormMinimum);
        assertThat(message.getFrom(), is(mailsendFormMinimum.getFromAddr()));
    }

}

MAIL001MailHelper.java

    private String generateTextUsingVelocity(MailsendForm mailsendForm) {
        Constant constant = Constant.getInstance();
        Map<String, Object> model = new HashMap<>();
        model.put("name", mailsendForm.getName());
        model.put("sex", constant.SEX_MAP.get(mailsendForm.getSex()));
        model.put("type", constant.TYPE_MAP.get(mailsendForm.getType()));

        if (mailsendForm.getItem() != null) {
            String itemList = mailsendForm.getItem().stream()
                    .map(constant.ITEM_MAP::get)
                    .collect(Collectors.joining(", "));
            model.put("item", itemList);
        }
            
        model.put("naiyo", mailsendForm.getNaiyo());
        return velocityUtils.merge(this.templateLocation, model);
    }
  • getItem() が null かチェックする if (mailsendForm.getItem() != null) { ... } を追加します。

build.gradle

dependencies {
    def jdbcDriver = "org.postgresql:postgresql:9.4-1201-jdbc41"

    // spring-boot-gradle-plugin によりバージョン番号が自動で設定されるもの
    // Appendix E. Dependency versions ( http://docs.spring.io/spring-boot/docs/current/reference/html/appendix-dependency-versions.html ) 参照
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework.boot:spring-boot-starter-thymeleaf")
    compile("org.springframework.boot:spring-boot-starter-data-jpa")
    compile("org.springframework.boot:spring-boot-starter-velocity")
    compile("org.springframework.boot:spring-boot-starter-mail")
    compile("org.codehaus.janino:janino")
    testCompile("org.springframework.boot:spring-boot-starter-test")
    testCompile("org.yaml:snakeyaml")

    // spring-boot-gradle-plugin によりバージョン番号が自動で設定されないもの
    compile("${jdbcDriver}")
    compile("org.seasar.doma:doma:2.2.0")
    compile("org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16")
    compile("org.apache.commons:commons-lang3:3.4")
    compile("org.projectlombok:lombok:1.16.2")
    testCompile("org.dbunit:dbunit:2.5.0")
    testCompile("org.subethamail:subethasmtp:3.1.7")
    testCompile("com.icegreen:greenmail:1.4.1")

    // for Doma-Gen
    domaGenRuntime("org.seasar.doma:doma-gen:2.2.0")
    domaGenRuntime("${jdbcDriver}")
}
  • testCompile("org.subethamail:subethasmtp:3.1.7") を追加します。
  • testCompile("com.icegreen:greenmail:1.4.1") を追加します。

MailServerWiserResource.java

package ksbysample.webapp.email.test;

import org.junit.rules.ExternalResource;
import org.springframework.stereotype.Component;
import org.subethamail.wiser.Wiser;

@Component
public class MailServerWiserResource extends ExternalResource {

    private Wiser wiser = new Wiser();

    @Override
    protected void before() {
        this.wiser.setHostname("localhost");
        this.wiser.setPort(25);
        this.wiser.start();
    }

    @Override
    protected void after() {
        this.wiser.stop();
    }

    public Wiser getWiser() {
        return this.wiser;
    }

}

EmailServiceTest.java

■その1

package ksbysample.webapp.email.service;

import ksbysample.webapp.email.Application;
import ksbysample.webapp.email.test.MailServerWiserResource;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.subethamail.wiser.WiserMessage;

import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.List;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.*;

public class EmailServiceTest {

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = Application.class)
    @WebAppConfiguration
    public static class Wiserを利用してメール送信する場合 {

        @Rule
        @Autowired
        public MailServerWiserResource wiser;

        @Autowired
        private EmailService emailService;

        @Test
        public void testSendSimpleMail() throws Exception {
            SimpleMailMessage message = new SimpleMailMessage();
            message.setFrom("test@sample.com");
            message.setTo("xxx@yyy.zzz");
            message.setSubject("テスト");
            message.setText("これはテストです");
            emailService.sendSimpleMail(message);

            List<WiserMessage> receiveMessages = wiser.getWiser().getMessages();
            assertThat(receiveMessages.size(), is(1));
            MimeMessage receiveMessage = receiveMessages.iterator().next().getMimeMessage();
            assertThat(receiveMessage.getFrom()[0], is(new InternetAddress("test@sample.com")));
            assertThat(receiveMessage.getAllRecipients()[0], is(new InternetAddress("xxx@yyy.zzz")));
            assertThat(receiveMessage.getSubject(), is("テスト"));
            assertThat(receiveMessage.getContent(), is("これはテストです"));
        }

    }

}

■その2

package ksbysample.webapp.email.service;

import com.icegreen.greenmail.junit.GreenMailRule;
import com.icegreen.greenmail.util.GreenMail;
import com.icegreen.greenmail.util.GreenMailUtil;
import com.icegreen.greenmail.util.ServerSetup;
import com.icegreen.greenmail.util.ServerSetupTest;
import ksbysample.webapp.email.Application;
import ksbysample.webapp.email.test.MailServerWiserResource;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.subethamail.wiser.WiserMessage;

import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.List;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.*;

public class EmailServiceTest {

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = Application.class)
    @WebAppConfiguration
    public static class Wiserを利用してメール送信する場合 {

        @Rule
        @Autowired
        public MailServerWiserResource wiser;

        @Autowired
        private EmailService emailService;

        @Test
        public void testSendSimpleMail() throws Exception {
            SimpleMailMessage message = new SimpleMailMessage();
            message.setFrom("test@sample.com");
            message.setTo("xxx@yyy.zzz");
            message.setSubject("テスト");
            message.setText("これはテストです");
            emailService.sendSimpleMail(message);

            List<WiserMessage> receiveMessages = wiser.getWiser().getMessages();
            assertThat(receiveMessages.size(), is(1));
            MimeMessage receiveMessage = receiveMessages.iterator().next().getMimeMessage();
            assertThat(receiveMessage.getFrom()[0], is(new InternetAddress("test@sample.com")));
            assertThat(receiveMessage.getAllRecipients()[0], is(new InternetAddress("xxx@yyy.zzz")));
            assertThat(receiveMessage.getSubject(), is("テスト"));
            assertThat(receiveMessage.getContent(), is("これはテストです"));
        }

    }

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = Application.class)
    @WebAppConfiguration
    public static class GreenMailを利用してメール送信する場合 {

        @Rule
        public GreenMailRule greenMail = new GreenMailRule(new ServerSetup(25, "localhost", ServerSetup.PROTOCOL_SMTP));

        @Autowired
        private EmailService emailService;

        @Test
        public void testSendSimpleMail() throws Exception {
            SimpleMailMessage message = new SimpleMailMessage();
            message.setFrom("test@sample.com");
            message.setTo("xxx@yyy.zzz");
            message.setSubject("テスト");
            message.setText("これはテストです");
            emailService.sendSimpleMail(message);

            MimeMessage[] receivedMessages = greenMail.getReceivedMessages();
            assertThat(receivedMessages.length, is(1));
            assertThat(receivedMessages[0].getFrom()[0], is(new InternetAddress("test@sample.com")));
            assertThat(receivedMessages[0].getAllRecipients()[0], is(new InternetAddress("xxx@yyy.zzz")));
            assertThat(receivedMessages[0].getSubject(), is("テスト"));
            // GreenMailUtil.getBody を使用すると取得した日本語のメール本文が
            // "44GT44KM44Gv44OG44K544OI44Gn44GZ"
            // でした。デコードが必要?
            //assertThat(GreenMailUtil.getBody(receivedMessages[0]), is("これはテストです"));
            assertThat(receivedMessages[0].getContent(), is("これはテストです"));
        }

    }

}
  • public static class GreenMailを利用してメール送信する場合 { ... } を追加します。

■その3

package ksbysample.webapp.email.service;

import com.icegreen.greenmail.junit.GreenMailRule;
import com.icegreen.greenmail.util.ServerSetup;
import ksbysample.webapp.email.Application;
import ksbysample.webapp.email.test.MailServerResource;
import ksbysample.webapp.email.test.MailServerWiserResource;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.subethamail.wiser.WiserMessage;

import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.List;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

@RunWith(Enclosed.class)
public class EmailServiceTest {

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = Application.class)
    @WebAppConfiguration
    public static class Wiserを利用してメール送信する場合 {

        @Rule
        @Autowired
        public MailServerWiserResource wiser;

        @Autowired
        private EmailService emailService;

        @Test
        public void testSendSimpleMail() throws Exception {
            SimpleMailMessage message = new SimpleMailMessage();
            message.setFrom("test@sample.com");
            message.setTo("xxx@yyy.zzz");
            message.setSubject("テスト");
            message.setText("これはテストです");
            emailService.sendSimpleMail(message);

            List<WiserMessage> receiveMessages = wiser.getWiser().getMessages();
            assertThat(receiveMessages.size(), is(1));
            MimeMessage receiveMessage = receiveMessages.iterator().next().getMimeMessage();
            assertThat(receiveMessage.getFrom()[0], is(new InternetAddress("test@sample.com")));
            assertThat(receiveMessage.getAllRecipients()[0], is(new InternetAddress("xxx@yyy.zzz")));
            assertThat(receiveMessage.getSubject(), is("テスト"));
            assertThat(receiveMessage.getContent(), is("これはテストです"));
        }

    }

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = Application.class)
    @WebAppConfiguration
    public static class GreenMailを利用してメール送信する場合 {

        @Rule
        public GreenMailRule greenMail = new GreenMailRule(new ServerSetup(25, "localhost", ServerSetup.PROTOCOL_SMTP));

        @Autowired
        private EmailService emailService;

        @Test
        public void testSendSimpleMail() throws Exception {
            SimpleMailMessage message = new SimpleMailMessage();
            message.setFrom("test@sample.com");
            message.setTo("xxx@yyy.zzz");
            message.setSubject("テスト");
            message.setText("これはテストです");
            emailService.sendSimpleMail(message);

            MimeMessage[] receivedMessages = greenMail.getReceivedMessages();
            assertThat(receivedMessages.length, is(1));
            assertThat(receivedMessages[0].getFrom()[0], is(new InternetAddress("test@sample.com")));
            assertThat(receivedMessages[0].getAllRecipients()[0], is(new InternetAddress("xxx@yyy.zzz")));
            assertThat(receivedMessages[0].getSubject(), is("テスト"));
            // GreenMailUtil.getBody を使用すると取得した日本語のメール本文が
            // "44GT44KM44Gv44OG44K544OI44Gn44GZ"
            // でした。デコードが必要?
            //assertThat(GreenMailUtil.getBody(receivedMessages[0]), is("これはテストです"));
            assertThat(receivedMessages[0].getContent(), is("これはテストです"));
        }

    }

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = Application.class)
    @WebAppConfiguration
    public static class MailServerResourceを利用してメール送信する場合 {

        @Rule
        @Autowired
        public MailServerResource mailServer;

        @Autowired
        private EmailService emailService;

        @Test
        public void testSendSimpleMail() throws Exception {
            SimpleMailMessage message = new SimpleMailMessage();
            message.setFrom("test@sample.com");
            message.setTo("xxx@yyy.zzz");
            message.setSubject("テスト");
            message.setText("これはテストです");
            emailService.sendSimpleMail(message);

            assertThat(mailServer.getMessagesCount(), is(1));
            MimeMessage receiveMessage = mailServer.getFirstMessage();
            assertThat(receiveMessage.getFrom()[0], is(new InternetAddress("test@sample.com")));
            assertThat(receiveMessage.getAllRecipients()[0], is(new InternetAddress("xxx@yyy.zzz")));
            assertThat(receiveMessage.getSubject(), is("テスト"));
            assertThat(receiveMessage.getContent(), is("これはテストです"));
        }

    }

}
  • テストクラス内のネストしたテストクラスを全てテストすることが出来ないことに気づきましたので、@RunWith(Enclosed.class) を追加します。
  • public static class MailServerResourceを利用してメール送信する場合 { ... } を追加します。

MailServerResource.java

package ksbysample.webapp.email.test;

import com.icegreen.greenmail.util.GreenMail;
import com.icegreen.greenmail.util.ServerSetup;
import org.junit.rules.ExternalResource;
import org.springframework.stereotype.Component;

import javax.mail.internet.MimeMessage;
import java.util.Arrays;
import java.util.List;

@Component
public class MailServerResource extends ExternalResource {

    private GreenMail greenMail = new GreenMail(new ServerSetup(25, "localhost", ServerSetup.PROTOCOL_SMTP));

    @Override
    protected void before() {
        greenMail.start();
    }

    @Override
    protected void after() {
        greenMail.stop();
    }

    public int getMessagesCount() {
        return greenMail.getReceivedMessages().length;
    }

    public List<MimeMessage> getMessages() {
        return Arrays.asList(greenMail.getReceivedMessages());
    }

    public MimeMessage getFirstMessage() {
        MimeMessage message = null;
        MimeMessage[] receivedMessages = greenMail.getReceivedMessages();
        if (receivedMessages.length > 0) {
            message = receivedMessages[0];
        }
        return message;
    }

}

履歴

2015/05/17
初版発行。