NUnit で DBUnit もどきを使う

データベースアクセスがある場合は、DBUnit を使うのがベストなんでしょうが、ひとまず、初期データの投入だけできればいいや、って気持ちで作ったのがこれです。

public class DBTest
{
    public static void DataSetup( IDataTable tbl, SqlConnection cn )
    {
        Type RowType = tbl.GetRowType();
        string TableName = tbl.GetTableName();


        PropertyInfo[] pis = typeof(XProductRow).GetProperties();

        string sql_columns = "(";
        string sql_values = "(";
        foreach (PropertyInfo pi in pis)
        {
            sql_columns += pi.Name + ",";
            sql_values += "@" + pi.Name + ",";
        }
        // 最後のカンマを削除
        sql_columns = sql_columns.Substring(0, sql_columns.Length - 1);
        sql_values = sql_values.Substring(0, sql_values.Length - 1);
        string sql = "insert into " + TableName+ " "
            + sql_columns + ") values "
            + sql_values + ")";


        SqlCommand cmd = new SqlCommand(sql, cn);
        foreach (PropertyInfo pi in pis)
        {
            SqlParameter param = new SqlParameter();
            param.ParameterName = pi.Name;
            cmd.Parameters.Add(param);
        }

        cmd.Connection.Open();
        foreach ( object item in tbl.GetList())
        {
            foreach( PropertyInfo pi in pis ) {
                cmd.Parameters[pi.Name].Value = pi.GetValue(item,null);
            }
            cmd.ExecuteNonQuery();
        }
        cmd.Connection.Close();
    }
}

例のごとく、リフレクションを使ってプロパティ名=テーブルのカラム名と想定して、INSERT 文を作成します。Visual Studio で作成される型付 DataSet を使っても良いのですが、データ投入をするたびに、別の DataAdapter を呼び出さないといけないし、なんかいまいちなので、ってのと、テストデータの投入なので INSERT 文と、テーブルの中身を DELETE する部分だけが欲しい訳で、型付 DataSet だと冗長なんですよね。

/// <summary>
/// リフレクションが簡単になるためのインターフェース
/// </summary>
public interface IDataTable
{
    string GetTableName();
    Type GetRowType();
    System.Collections.IList GetList();
}

/// <summary>
/// 商品クラス(カラム)
/// </summary>
public class XProductRow
{
    public string id { get; set; }
    public string name { get; set; }
    public int price { get; set; }
    public int cateid { get; set; }
}
/// <summary>
/// 商品クラス(テーブル)
/// </summary>
public class XProduct : IDataTable
{
    public XProduct() 
    {
        Rows = new List<XProductRow>();
    }
    public List<XProductRow> Rows { get; set; }
    public Type GetRowType() { return typeof(XProductRow); }
    public System.Collections.IList GetList() { return this.Rows; }
    public string GetTableName() { return "XProduct"; }
    public XProductRow NewRow() { return new XProductRow(); }
}

ざっくりと、POJO タイプの DataRow と、単なるコレクションを集めただけの DataTable を作っておきます。

そうして、データ投入をする場合は、

private void button1_Click(object sender, EventArgs e)
{
    // 自動でinsert文を作る
    SqlConnection cn = new SqlConnection(@"Data Source=.\sqlexpress;Initial Catalog=mvcdb;Integrated Security=True;MultipleActiveResultSets=True");

    XProduct table = new XProduct();
    XProductRow it = table.NewRow();
    it.id = "A8000";
    it.name = "新商品XXX";
    it.price = 2000;
    it.cateid = 2;
    table.Rows.Add(it);

    it = table.NewRow();
    it.id = "A8001";
    it.name = "新商品YYY";
    it.price = 2000;
    it.cateid = 2;
    table.Rows.Add(it);

    DBTest.DataSetup(table, cn);
}

こんな風に、DataRow/DataTable にデータを詰めておいて、一気にセットアップできます。

C# v3.0 の場合は、こんな風に初期化しながらということもできます。

table.Rows.Add(
    new XProductRow
    {
        id = "A8002",
        name = "新商品ZZZ",
        price = 20000,
        cateid = 1
    });

まあ、これで良いかなぁと。

カテゴリー: C#, xUnit パーマリンク