문제

I tried to find an example of this but without success so that's is why I asked this question.

Lets start with some code. Here's my code:

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

And my test code:

[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();
    }
}

Here's what I'm trying to do. I want to, before execution of each test method, look to the test method and check if methods DoDummyThings1,DoDummyThings2 and DoDummyThings3 of Dummy class will be called or not.

The purpose of this is, depending of which DoDummyThingsX methods are called, I want to inject different implementation somewhere deep inside the code to modify during runtime the behavior of some class (swap the inject implementation of an interface for another one).

Can somebody explain me how to do this correctly (with lastest version of Cecil or something else for C#)? Is there a way to do this without using the .dll files? (Currently, this is the only way I figured out how to do this but, using strings as "MyDllName.dll" and "MyNamespace.MyClassName" hard coded are not possible for me)

Other stackoverflow threads I'm already aware of:

Can anyone help me with a complete (but simple) example (if it's possible)? Thank you!

도움이 되었습니까?

해결책

This answer demonstrates how to determine which tests execute a Dummy method but does not answer:

inject different implementation somewhere deep inside the code to modify during runtime the behavior of some class

Reflection doesn't provide granular access to the IL Body of the unit test methods which you will need; however Cecil provides this functionality. The following linq returns a list of methods that internally call DoDummyThings1. The linq could be more efficient but I wanted to make it as clear as possible. The where clause is the important part.

//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();

Disassemble the test assembly using ILDasm to figure out the OpCodes / Operands. The relevant part of the TestDummy method will be something like:

  //this.dum.DoDummyThings1();
  IL_0001:  ldarg.0
  IL_0002:  ldfld      class Lib.Dummy Lib.UnitTest::dum
  IL_0007:  callvirt   instance void Lib.Dummy::DoDummyThings1()
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top