如何验证是否在另一个方法中调用了一个方法

时间:2013-06-14 21:10:55

标签: c# reflection mstest system.reflection mono.cecil

我试图找到一个例子,但没有成功,这就是我问这个问题的原因。

让我们从一些代码开始。这是我的代码:

class Dummy
{
    public void DoDummyThings1()
    {
        Console.WriteLine("Sorry, I'm dummy 1...");
    }

    public void DoDummyThings2()
    {
        Console.WriteLine("Sorry, I'm dummy 2...");
    }

    public void DoDummyThings3()
    {
        Console.WriteLine("Sorry, I'm dummy 3...");
    }
}

我的测试代码:

[TestClass]
public class UnitTest
{
    private Dummy dum = new Dummy();

    [TestInitialize()]
    public void SetUp()
    {
        MethodInfo mi = typeof (UnitTest).GetMethod("TestDummy");
        MethodBody mb = mi.GetMethodBody();
    }

    [TestMethod]
    public void TestDummy()
    {
        this.dum.DoDummyThings1();
        this.dum.DoDummyThings2();
        this.dum.DoDummyThings3();
    }
}

这就是我想要做的。我想在执行每个测试方法之前,查看测试方法并检查是否会调用Dummy类的方法DoDummyThings1,DoDummyThings2和DoDummyThings3。

这样做的目的是,根据调用哪些DoDummyThingsX方法,我想在代码内部的某处注入不同的实现,以在运行时修改某些类的行为(将接口的注入实现交换为另一个类)。

有人可以解释我如何正确地做到这一点(使用最新版本的Cecil或C#的其他内容)? 有没有办法在不使用.dll文件的情况下执行此操作? (目前,这是我弄清楚如何执行此操作的唯一方法,但是使用字符串作为“MyDllName.dll”和“MyNamespace.MyClassName”硬编码对我来说是不可能的)

我已经知道的其他stackoverflow线程:

任何人都可以帮我一个完整的(但很简单的)例子(如果可能的话)? 谢谢!

1 个答案:

答案 0 :(得分:2)

此答案演示了如何确定哪些测试执行Dummy方法但未回答:

  

在代码深处的某处注入不同的实现,以在运行时修改某些类的行为

Reflection不提供对您需要的单元测试方法的IL Body的细粒度访问;但Cecil提供此功能。以下linq返回内部调用DoDummyThings1的方法列表。 linq可能更有效但我想尽可能清楚。 where子句是重要的部分。

//syntax based on version 0.9.5.4 (http://nuget.org/packages/Mono.Cecil/0.9.5.4)
using Mono.Cecil;  
using Mono.Cecil.Cil;
//...
string assemblyPath = (@"path to your unit test assembly\MyTests.dll");
AssemblyDefinition asm = AssemblyDefinition.ReadAssembly(assemblyPath);

List<MethodDefinition> testsThatCallDummyMethods =
       (from mod in asm.Modules
        from t in mod.Types
        from meth in t.Methods
        where meth.HasBody
        from instr in meth.Body.Instructions
        let op = instr.Operand as MethodDefinition
        where
            instr.OpCode == OpCodes.Callvirt &&
            op != null &&
            op.DeclaringType.FullName ==
            "Lib.Dummy" //namespace qualified type name
            && op.Name ==
            "DoDummyThings1" //method names...
        select meth)
        .ToList();

使用ILDasm反汇编测试程序集以找出操作码/操作数。 TestDummy方法的相关部分将类似于:

  //this.dum.DoDummyThings1();
  IL_0001:  ldarg.0
  IL_0002:  ldfld      class Lib.Dummy Lib.UnitTest::dum
  IL_0007:  callvirt   instance void Lib.Dummy::DoDummyThings1()