2013-01-24 6 views
1

나는 테스트의 방법이 거의없고 많은 양의 코드가 최근에 변경된 프로젝트에 참여하고 있습니다. 특히 코드가 하나의 데이터 공급자를 사용하여 다른 곳으로 이동하고 DataSet이 DTO로 대체되었습니다.IL에서 C# 로의 변환

나는 이것을 가능한 한 많이 테스트하려고하지만, 필요한 시간 내에 수많은 사람들이 한 모든 변경 사항에 대한 테스트를 현실적으로 만들 수는 없습니다.

Mono.cecil을 사용하여 모든 데이터베이스 호출과 관련 저장 프로 시저 이름을 찾고 C#에 정의 된 매개 변수를 데이터베이스의 매개 변수와 비교하는 테스트를 작성할 수있었습니다.

모든 매개 변수가 기본값 인 경우에도이 한 걸음 더 나아가 실제로 메서드를 호출하고 싶습니다. 이 방법은 DataReader에 행이 없을 수도 있지만 스키마를 발견하고이를 정적 매퍼 메서드와 비교해 볼 수 있습니다.

예를 들어

GetRows()가 단순 확장 방법이며 GetDivisionFromRecord를 변환하는 방법을 알아낼 수 없습니다 I Unfortunatley이

public static Division GetDivisionFromRecord(record) 
{ 
    return new Division 
    { 
     Id = record.GetValueOrDefault<long?>("id"), 
     Name = record.GetValueOrDefault<string>("name") 
    }; 
} 

처럼 조금 보이는 정적 방법이다

var reader = cmd.ExecuteReader(); 
var Divisions = (from IDataRecord record in reader.GetRows() 
select RecordMapper.GetDivisionFromRecord(record)).ToList(); 

IL은 mapper 클래스의 정적 메서드 이름으로 캐시 된 정적 대리자를 참조합니다. 메소드 이름을 찾을 수 있다면 Cecil을 사용하여 메소드를 가져오고 GetValueOrDefault에 callvirt opcode를 찾아 데이터베이스 별칭 및 유형 모음을 빌드 할 수 있습니다.

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>) 

저는 세실과 리플렉션을 모두 사용했으며 CachedAnonymousDelegates를 개인 정적 필드로 볼 수 있습니다. 그러나 실제 메서드 호출을 얻는 방법을 알 수 있습니다.

어떻게 생각해도 될까요?

+0

Telerik은 .NET 어셈블리를 디 컴파일하려는 경우 무료 디 컴파일러를 제공합니다. 아마 시간을 절약 할 수있을 것입니다. 리플렉터와 달리 아직 무료입니다. http://www.telerik.com/products/decompiler.aspx (그리고 나는 Telerk와 아무런 관련이 없기 때문에 공개 할 필요가 없습니다.) – David

+3

이것은 이상한 방법입니다. 소스 제어에있는 버전에 대해 diff를 실행하여 테스트해야 할 항목을 찾으십시오. –

+0

이미 디 컴파일러 mono.cecil을 사용하고 있습니다. Reflector/ILSpy 등의 도구를 사용하고 싶지는 않습니다. 그 이후로 전체 테스트 프로세스가 수동으로 진행될 것이고 회귀 테스트에 사용할 수있는 테스트 케이스가 없을 것이고 데이터베이스 릴리스 등을 확인할 수도 있습니다. – hugo

답변

1

결국 나는 ICSharpCode.Decompiler와 ICSharpCode.NRefactory에서 AstBuilder를 사용하여 관련 IL을 Mono.cecil에서 C#으로 다시 변환하여 정규식을 사용하여 매퍼를 찾을 수있게했습니다.

이 접근법을 사용하면 먼저이 모든 메타 데이터를 사용하여 처음부터 완료되어 야 할 수백 가지 테스트를 생성합니다.