modest violet

読者です 読者をやめる 読者になる 読者になる

modest violet

開発者としてのあれこれや、日々の雑記など

your future hasn't written yet. no one's has.
by Emmett Lathrop "Doc" Brown

AutoMapper6でのプロファイル設定とユニットテスト

AutoMapperという自動マッピングライブラリーが便利なのです。ただ、少しばかり使い方を誤っていたようで、下記のサイトを参考に再勉強させて頂きました。

iyemon018.hatenablog.com

この記事のお陰で、今までの自分があまりにも恩恵を受けない無駄な記載をいっぱいしていたという事に気づきました。例えば、逆マッピングもわざわざ定義を書いていたとか、同じ名前のオブジェクトもわざわざ定義書いていたりだとか・・・。

いざ自分でも定義をプロファイル単位にしようと試していたのですが、どうも仕様が違っている様子・・・。
最新のAutoMapperは6.0.2になっており、プロファイルのオーバーライド辺りが変更になっていたようです。ですので、自分の備忘録も兼ねて手順を記載します。

マッピングの定義

以前のAutoMapperでは、Configure()メソッドをオーバーライドして定義を書いていましたが、バージョン6以降は互換がなくなったようで、コンストラクターに定義を記載する事になります。

public class HogeProfile : Profile
{
    // コンストラクターでマッピング定義を記載します
    public HogeProfile()
    {
        CreateMap<SourceClass, DestinationClass>()
            .ForMember(d => d.XXXXXXXXXX, o => o.MapFrom(s => s.YYYYYYYYYY))
            .ReverseMap()
            .ForMember(s => s.XXXXXXXXXX, o => o.MapFrom(d => d.YYYYYYYYYY))
            ;
    }
}


上記のように、必要な定義ごとにクラスを分ける方が管理しやすくて良いと思います。以前一つのクラスの中に定義をまとめて書いていたのですが、数が多くなると判りにくくて仕方が無いという経験からの意見です。

作成したプロファイル設定は、ASP.NET MVCであればGlobal.asaxなどに呼び出しの記述を行います。

Mapper.Initialize(config =>
    {
        config.AddProfile<HogeProfile >();
        config.AddProfile<HogeHogeProfile>();
    });

// マッピング設定の検証
Mapper.AssertConfigurationIsValid();

マッピングユニットテスト

基本的にそのまま値の受け渡しが行われるので、ユニットテストは不要という考えもできます。
但し、型が違うことによりAutoMapperで変換をかけたり、固定値を入れたりなど絶対不要か、といえばそうでも無いと思います。ユニットテストを書く癖をつけるためにも書いてみました。

簡単ですが、MSTestで書いたテストクラスはこんな感じです。

[TestClass()]
public class HogeProfileTests
{
    [ClassInitialize]
    public static void ClassInit(TestContext context)
    {
        Mapper.Initialize(config =>
        {
            // Global.asaxの呼び出し代わりにClassInitializeでプロファイルを呼び出しておく
            config.AddProfile<HogeProfile>(); 
        }); 
    }

    [TestMethod()]
    public void マッピング設定の検証()
    {
        // マッピングエラーならException
        Mapper.AssertConfigurationIsValid();
    }

    [TestMethod()]
    public void コピー元からコピー先へのマッピング検証()
    {
        var srcModel = new SourceClass()
        {
            // コピー元の値を適当に設定
        };

        var destModel = Mapper.Map<DestinationClass>(srcModel);

        // コピー元とコピー先で値が同じか
        Assert.AreEqual(destModel.xxxxxx, srcModel.xxxxxx); 

    //以下・・・省略
    
    }


    [TestMethod()]
    public void コピー先からコピー元への逆マッピング検証()
    {
        var destModel = new DestinationClass()
        {
            // コピー先の値を適当に設定
        };

        var srcModel = Mapper.Map<SourceClass>(destModel);

        // コピー元とコピー先で値が同じか
        Assert.AreEqual(srcModel.CategoryId, destModel.CategoryId);

        //以下・・・省略

    }
}


名前や型が同じプロパティー部分は比較検証しなくてもいいかな、というのが率直な感想です。
AutoMapperで何かしらのマッピング定義を施した箇所を中心にテストを作成するのが合理的だと思います。