Seasar DI Container with AOP

Maiのテスト

テンプレートに想定通りにデータが埋め込まれているか確かめたい。でもテストは自動化したいので、実行の度にSMTPサーバに送信されては困る。

そのような場合に対応出来るよう、S2Maiではテスト用のクラスを用意しています。

テストの方法には、専用のS2MaiTestCaseクラスを継承してテストクラスを作る方法と、任意のテストクラスからS2Maiテスト用ユーティリティクラスを使う方法の2通りがあります。

セットアップ

diconファイル

s2mai.diconの代わりに、s2mai_test.diconを使います。s2mai.diconが使われている場合、テスト実行時にエラーになります。

test.dicon
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
	"http://www.seasar.org/dtd/components24.dtd">
<components>
    <include path="s2mai_test.dicon"/>
	
</components>

SMART deployの場合、このdiconファイルを、S2TestCaseを継承したテストクラスのinclude()で読み込めば、Maiのテストは可能です。SMART deployでない場合、適宜テスト対象のMaiインタフェースにアスペクトの設定をして下さい。設定方法は本番の場合と同じです。

<include path="s2mai_test.dicon"/>
<component class="com.example.TestMai">
    <aspect>s2MaiInterceptor</aspect>
</component>

また、SMART deployの場合、app.diconに条件インクルードを用いて設定してもよいでしょう。

app.dicon
<include condition="#ENV == 'ut'" path="s2mai_test.dicon"/>
<include condition="#ENV != 'ut'" path="s2mai.dicon"/>

期待値テキストファイルの準備

S2Maiがテンプレートファイルを読み込んで出力すると期待される内容を、テキストファイルで作成し、保存します。保存先はテストクラスと同じパッケージにすると後々楽です。

例えば、テンプレートが以下の内容だとします。

TestMai_sendMail.ftl
Subject: てすとまいです。No.${data.number}
 
 ここからデータ。
 ${data.text}

そして、送信内容として下記のようになる事を期待するとします。

TestMaiTest_expected.txt
Subject: てすとまいです。No.4
 
ここからデータ。
埋め込みデータはこんな感じで。
改行も入れてみるか。

期待値テキストファイルの拡張子は任意のものでかまいません。文字コードはmailProperties.diconで設定したtemplateEncodingの値に合わせて下さい。デフォルトはUTF-8です。また、改行コードは、テンプレートに合わせて下さい。

期待値テキストファイルの「Subject: 」は省略する事も出来ます。その場合は、後述する期待値のMailクラスのSubjectプロパティに件名をセットして下さい。

S2MaiTestCaseを使う方法

S2Maiでは、S2TestCaseを拡張したS2MaiTestCaseを提供しています。まず、S2MaiTestCaseを継承してテストクラスを作ります。ここでは、TestMaiというMaiインターフェースをテストします。

import org.seasar.mai.unit.S2MaiTestCase;
import com.ozacc.mail.Mail;

public class TestMaiTest extends S2MaiTestCase {

    private TestMai testMai;
    
    protected void setUp() throws Exception{
        include("app.dicon");
    }
    
    public void testメール送信(){
        TestMaiDto dto = new TestMaiDto();
        dto.setFrom("hoge@example.com");
        dto.setTo("fuga@foo.co.jp");
        dto.setText("埋め込みデータはこんな感じで。\r\n改行も入れてみるか。");
        dto.setNumber("4");
        
        Mail expected = createExpectedMailByFile("TestMaiTest_expected.txt");
        expected.setFrom("hoge@example.com");
        expected.addTo("fuga@foo.co.jp");

        testMai.sendMail(dto);

        Mail actual = getActualMail(0);

        assertEquals(expected, actual);
    }

}

まず、実際の処理のようにTestMai#sendMail()の引数となるDtoを設定します。

次に、実行結果として期待されるMailオブジェクトを生成します。createExpectedMailByFile(String)というメソッドを使います。

Mail expected = createExpectedMailByFile("TestMaiTest_expected.txt");

引数に先程作成した期待値テキストファイルの名前を指定すると、それを本文としたMailオブジェクトを生成して戻します。期待値テキストファイルがテストクラスと同じパッケージにある場合は、パスを書かずにファイル名だけでOKです。

この状態だと、期待値Mailオブジェクトには本文の内容と、期待値テキストファイルに「Subject: 」を書いた場合はSubjectプロパティのみがセットされています。他のプロパティを検証する場合は適宜プロパティに値をセットします。この場合、Dtoにセットした内容がきちんとMailオブジェクトに反映される事が期待されるので、以下のようになります。

expected.setFrom("hoge@example.com");
expected.addTo("fuga@foo.co.jp");

テスト対象のMaiのメール送信メソッドを実行した後、getActualMail(int)というメソッドで、実行結果としてS2Maiが生成したMailオブジェクトを取得します。

testMai.sendMail(dto);

Mail actual = getActualMail(0);

1つのテストメソッドの中で複数回メール送信処理が実行された場合にも対応しています。それぞれの処理の結果をリストで保持しているので、第1引数に取得したい実行結果のインデックスを指定します。1回目の送信の結果は0、2回目の送信の結果は1を指定すると取得出来ます。これはテストメソッド実行前に自動的に初期化されます。

これで、期待値のMailオブジェクトと、実際の値のMailオブジェクトが取得出来たので、assertEquals(Mail, Mail)で検証します。内部的に、それぞれのMailオブジェクトをtoString()で文字列に変換し、比較しています。

ユーティリティクラスを使う方法

S2MaiTestCaseではない任意のテストクラスから検証したい場合もあるかと思います。その場合は、SendMailTestUtilというテスト用のユーティリティクラスがありますので、そちらを利用します。先程のテストをS2TestCaseで書き直します。


public class TestMaiTest extends S2TestCase {

    private TestMai testMai;
    
    protected void setUp() throws Exception{
        include("app.dicon");
        SendMailTestUtil.init();
    }
    
    public void testメール送信(){
        TestMaiDto dto = new TestMaiDto();
        dto.setFrom("hoge@example.com");
        dto.setTo("fuga@foo.co.jp");
        dto.setText("埋め込みデータはこんな感じで。\r\n改行も入れてみるか。");
        dto.setNumber("4");
        
        Mail expected = SendMailTestUtil.createExpectedMailByFile(this, "TestMaiTest_expected.txt");
        expected.setFrom("hoge@example.com");
        expected.addTo("fuga@foo.co.jp");

        testMai.sendMail(dto);

        Mail actual = SendMailTestUtil.getActualMail(0);

        assertEquals(expected.toString(), actual.toString());
    }

}

まず、setUpメソッドの中で、かならず初期化して下さい。

protected void setUp() throws Exception{
    include("app.dicon");
    SendMailTestUtil.init();
}

期待値Mailを取得する時は、S2MaiTestCaseの時と違い、第1引数にthisを指定して下さい。

Mail expected = SendMailTestUtil.createExpectedMailByFile(this, "TestMaiTest_expected.txt");

実行結果のMailの取得方法はほぼ同じです。検証する場合は、それぞれtoString()して比較するとよいでしょう。

assertEquals(expected.toString(), actual.toString());