1

我正在开发一个项目,该项目的测试方式很少,并且最近更改了大量代码。特别是代码已从使用一个数据提供程序移植到另一个数据提供程序,并且 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 视为私有静态字段。但我可以看到如何获得实际的方法调用。

有什么想法可以解决这个问题吗?

4

1 回答 1

1

最后,我使用 ICSharpCode.Decompiler 和 ICSharpCode.NRefactory 中的 AstBuilder 将相关 IL 从 Mono.cecil 转换回 c#,这样我就可以使用正则表达式来发现映射器。

使用这种方法,我使用所有这些元数据来生成数百个测试,这些测试应该首先完成。

于 2013-01-25T11:59:03.430 回答