2013-01-24 66 views
1

我正在開發一個項目,它的測試方式很少,而且大量的代碼最近已經發生了變化。特別是代碼已經從使用一個數據提供者移植到另一個數據提供者,並且DataSet已被DTO取代。IL到c#的轉換

我現在想盡可能地對此進行測試,但是不能實際地爲所需的時間範圍內衆多人員所做的所有更改進行測試。

使用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") 
    }; 
} 

Unfortunatley我無法弄清楚如何從轉換靜態方法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和reflection,並且可以將CachedAnonymousDelegates看作私有靜態字段。但我可以看到如何獲得實際的方法調用。

任何想法,我可以把它關閉?

+0

如果您只是想反編譯.NET程序集,Telerik會提供一個免費的反編譯器。它可能會爲你節省一些時間。與反射器不同,它仍然是免費的。 http://www.telerik.com/products/decompiler.aspx(而我與Telerk沒有任何關係,所以沒有要透露的關係)。 – David

+3

這是一個奇怪的方法去做。只需在源代碼控制中的版本上運行差異,以找出應該測試的內容。 –

+0

我已經在使用反編譯器mono.cecil。我不想使用Reflector/ILSpy等工具,因爲整個測試過程都是手動的,我不會有可用於迴歸測試和驗證任何數據庫版本等的測試用例。 – hugo

回答

1

最後,我使用ICSharpCode.Decompiler和ICSharpCode.NRefactory中的AstBuilder將相關的IL從Mono.cecil轉換回c#,以便我可以使用正則表達式來發現映射器。

使用這種方法,我使用所有這些元數據來生成數百個應該首先完成的測試。