テストデータ追加・削除用 DataContext ヘルパー

担当プロジェクトの大きな修正のために、今週はずっとテストコードを書いています。ゴリゴリと。でも、いい加減飽きてきました。複数のデータベースの、これまた複数のテーブルを利用するので、テストデータを用意するのが大変。もうやめて!id:griefworker のライフはゼロよ!


さて、前に「テストデータの追加・削除を行うなら LINQ to SQL を使うと便利」みたいな内容の記事を書きました。

LINQ to SQL を使ってテストデータの作成・削除を楽にする - present

この方法だと、データベースに追加したテストデータをテストクラスが保持するので、コードが長くなりがちです。そこで、私は次のようなヘルパークラスを利用しています。

public class DataContextTestHelper<TDataContext>
    where TDataContext : System.Data.Linq.DataContext, new()
{
    public TDataContext Context { get; private set; }
    private List<object> _entities;

    public DataContextTestHelper()
        : this(new TDataContext())
    {
    }

    public DataContextTestHelper(TDataContext context)
    {
        _entities = new List<object>();
        Context = context;
    }

    // データベースにエンティティを登録する
    public void Setup(params object[] entities)
    {
        if (0 < entities.Length)
        {
            foreach (var entity in entities)
            {
                Context.GetTable(entity.GetType())
                       .InsertOnSubmit(entity);
            }

            // エンティティをキャッシュする
            _entities.AddRange(entities);

            // データベースに変更を反映
            using (TransactionScope ts = new TransactionScope())
            {
                Context.SubmitChanges();
                ts.Complete();
            }
        }
    }

    // データベースからエンティティを削除する
    public void Cleanup()
    {
        if (0 < _entities.Count)
        {
            foreach (var entity in _entities)
            {
                Context.GetTable(entity.GetType())
                       .DeleteOnSubmit(entity);
            }

            using (TransactionScope ts = new TransactionScope())
            {
                Context.SubmitChanges();
                ts.Complete();
            }
        }
    }
}

使い方は次の通りです。

private static DataContextTestHelper<FooDataContext> _helper =
    new DataContextTestHelper<FooDataContext>();

[ClassInitialize()]
public static void MyClassInitialize(TestContext testContext)
{
    // テストデータ作成
    Foo testData = new Foo();
    testData.Code1 = 9999;
    testData.Code2 = 999;
    testData.Name = "TEST";

    // テストデータをデータベースに保存
    _helper.Setup(testData);
}

[ClassCleanup()]
public static void MyClassCleanup()
{
    // テストデータをデータベースから削除
    _helper.Cleanup();
}

ヘルパーが内部にテストデータを保持しているので、テストデータをテストクラスが保持しなくて済みます。削除もメソッド呼び出しで一発。おかげでコード量もだいぶ減ります。地味に便利。

……用意するテストデータの量は変わらないですけどね。