DBのユニットテスト③ .NET

前回の続きです。
UserDaoをテストしやすくする為にユーティリティクラスを作ってみます。

App.config

前回書くの忘れてましたが、App.configはこんな感じになっています。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <connectionStrings>
      <add name="DataBase" 
           connectionString="Server=XXXXXXX\SQLEXPRESS;Initial Catalog=sample;User ID=sa;Password=XXXXXXX;" 
           providerName="System.Data.SqlClient" />
    </connectionStrings>
    <appSettings>
    </appSettings>
</configuration>

NDbUnitのインストール

NUnitはインストール済みとして・・・
dbunitの.NET版であるNDbUnitをインストールします。
ココからNDbUnitをダウンロードしてきます。
プロジェクト以下の適当なディレクトリに配置して参照設定すればインストール完了です。



DbTester.cs

Javaで作ったDbTesterの.NET版です。
NDbUnitはXML形式のテストデータファイルしか対応していないので、
XMLデータファイルでデータベースの初期化・アサートを行う実装にしました。


テストデータファイルの置き場所が変更になっても大丈夫なように、
SearchFilePath()で動的に検索できるようにしておきます。

using System;
using System.Data;
using System.IO;
using System.Windows.Forms;

using NDbUnit.Core;
using NDbUnitSample;

namespace NDbUnitSampleTest
{
    public class DbTester
    {
        private INDbUnitTest database;

        public DbTester(INDbUnitTest database)
        {
            this.database = database;
	}

        public DataSet CreateDataSet(string xsdFilePath, string xmlFilePath)
        {
            DataSet ds = new DataSet();
            ds.ReadXmlSchema(SearchFilePath(xsdFilePath));
            ds.ReadXml(SearchFilePath(xmlFilePath));
            return ds;
        }

        public void InitDb(string xsdFilePath, string xmlFilePath)
        {
            database.ReadXmlSchema(SearchFilePath(xsdFilePath));
            database.ReadXml(SearchFilePath(xmlFilePath));
            database.PerformDbOperation(DbOperationFlag.CleanInsertIdentity);
 	}

        public void AssertDb(string xsdFilePath, string xmlFilePath)
        {
            database.ReadXmlSchema(SearchFilePath(xsdFilePath));
            DataSet actual = database.GetDataSetFromDb();
            DataSet expected = CreateDataSet(xsdFilePath, xmlFilePath);
            DataSetAssert.AreEqual(expected, actual);
	}

        private string SearchFilePath(string filePath)
        {
            DirectoryInfo dir = new DirectoryInfo(Directory.GetCurrentDirectory());
            do
            {
                // ディレクトリ以下を検索
                String[] pathList = Directory.GetFiles(dir.FullName, Path.GetFileName(filePath), SearchOption.AllDirectories);
                foreach (string path in pathList)
                {
                    if (path.EndsWith(filePath.Replace('/', '\\'))) return path;
                }

                // 親ディレクトリに移動
                dir = dir.Parent;
            }
            while (dir != null);

            return null;
        }
    }
}

DataSetAssert.cs

NUnitのAssertでDataSetを比較するものがないみたいなので・・・作りました。
DataSet→DataTable→DataRowをひたすらAssertしていくクラスです。

using System;
using System.Data;

using NUnit.Framework;

namespace NDbUnitSampleTest
{
    public class DataSetAssert
    {
        public static void AreEqual(DataSet expected, DataSet actual)
        {
            Assert.AreEqual(expected.Tables.Count, actual.Tables.Count, "Different number of Tables");
            for (int i = 0; i < expected.Tables.Count; i++)
            {
                string tableName = expected.Tables[i].TableName;
                DataSetAssert.AreEqual(expected.Tables[tableName], actual.Tables[tableName]);
            }
        }

        public static void AreEqual(DataTable expected, DataTable actual)
        {
            Assert.AreEqual(expected.Rows.Count, actual.Rows.Count, "Different number of rows");
            for(int i = 0; i < expected.Rows.Count; i++)
            {
                DataSetAssert.AreEqual(expected.Rows[i], actual.Rows[i], i);
            }
        }

        public static void AreEqual(DataRow expected, DataRow actual, int rowIndex)
        {
            Assert.AreEqual(expected.ItemArray.Length, actual.ItemArray.Length, "Different number of columns");
            for (int i = 0; i < expected.ItemArray.Length; i++)
            {
                Assert.AreEqual(expected[i], actual[i], "Difference on row:" + rowIndex.ToString() + ", column:" + expected.Table.Columns[i]);
            }
        }

    }
}