私は、テストの方法がほとんどなく、最近大量のコードが変更されたプロジェクトに取り組んでいます。具体的には、あるデータ プロバイダーを使用していたコードが別のデータ プロバイダーに移植され、DataSet が DTO に置き換えられました。
これを可能な限りテストしたいと思いますが、必要な時間枠内に多数の人々によって行われたすべての変更に対して現実的にテストを作成することはできません.
Mono.cecil を使用して、すべてのデータベース呼び出しと関連するストアド プロシージャ名を検索し、C# で定義されたパラメーターとデータベース内のパラメーターを比較するテストを作成できました。
これをさらに一歩進めて、すべてのパラメーターがデフォルトであっても、実際にメソッドを呼び出したいと思います。この方法では、DataReader に行がない可能性がありますが、スキーマを発見し、これを静的マッパー メソッドと比較することができます。
例えば
var reader = cmd.ExecuteReader();
var Divisions = (from IDataRecord record in reader.GetRows()
select RecordMapper.GetDivisionFromRecord(record)).ToList();
GetRows() は単純な拡張メソッドで、GetDivisionFromRecord は次のような静的メソッドです。
public static Division GetDivisionFromRecord(record)
{
return new Division
{
Id = record.GetValueOrDefault<long?>("id"),
Name = record.GetValueOrDefault<string>("name")
};
}
残念ながら、キャッシュされた静的デリゲートへの IL 参照からマッパー クラスの静的メソッドの名前に変換する方法がわかりません。メソッド名を見つけることができれば、Cecil を使用してメソッドを取得し、GetValueOrDefault への callvirt オペコードを見つけて、データベースのエイリアスとタイプのコレクションを構築できます。
ILはこんな感じ。
IL_0025: callvirt instance class [System.Data]System.Data.IDataReader IOracleHelper::ExecuteReader(class OracleCommandWrapper)
IL_002a: stloc.0
IL_002b: ldloc.0
IL_002c: call class [mscorlib]System.Collections.Generic.IEnumerable`1<class [System.Data]System.Data.IDataRecord> NullSafeExtensions::GetRows(class [System.Data]System.Data.IDataReader)
IL_0031: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Cast<class [System.Data]System.Data.IDataRecord>(class [mscorlib]System.Collections.IEnumerable)
IL_0036: ldsfld class [System.Core]System.Func`2<class [System.Data]System.Data.IDataRecord, class [Services.Common]Division> DataDao::'CS$<>9__CachedAnonymousMethodDelegate17'
IL_003b: brtrue.s IL_0050
IL_003d: ldnull
IL_003e: ldftn class [Services.Common]Division DataDao::'<GetAlDivisions>b__16'(class [System.Data]System.Data.IDataRecord)
IL_0044: newobj instance void class [System.Core]System.Func`2<class [System.Data]System.Data.IDataRecord, class [Services.Common]Division>::.ctor(object, native int)
IL_0049: stsfld class [System.Core]System.Func`2<class [System.Data]System.Data.IDataRecord, class [Services.Common]Division> DataDao::'CS$<>9__CachedAnonymousMethodDelegate17'
IL_004e: br.s IL_0050
IL_0050: ldsfld class [System.Core]System.Func`2<class [System.Data]System.Data.IDataRecord, class [Services.Common]Division> DataDao::'CS$<>9__CachedAnonymousMethodDelegate17'
IL_0055: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!1> [System.Core]System.Linq.Enumerable::Select<class [System.Data]System.Data.IDataRecord, class [Services.Common]Division>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [System.Core]System.Func`2<!!0, !!1>)
IL_005a: call class [mscorlib]System.Collections.Generic.List`1<!!0> [System.Core]System.Linq.Enumerable::ToList<class [Services.Common]Division>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
私は cecil とリフレクションの両方を使用しており、CachedAnonymousDelegates をプライベートな静的フィールドとして見ることができます。しかし、実際のメソッド呼び出しを取得する方法はわかります。
どうすればこれをやってのけることができますか?