C#Moq拦截方法调用

C#Moq拦截方法调用,c#,moq,C#,Moq,我不确定我想做的是否可能。我有一个如下所示的界面: public interface IObject { void MethodA(ObjectA arg1); void MethodB(ObjectB arg1, ObjectC arg2); void MethodC(ObjectD arg1, ObjectE arg2); } 我有一些类似于以下实现的东西: public class ObjectImplementation : IObject {

我不确定我想做的是否可能。我有一个如下所示的界面:

public interface IObject
{
     void MethodA(ObjectA arg1);
     void MethodB(ObjectB arg1, ObjectC arg2);
     void MethodC(ObjectD arg1, ObjectE arg2);
}
我有一些类似于以下实现的东西:

public class ObjectImplementation : IObject
{
     public void MethodA(ObjectA arg1)
     {
          if(arg1.Something)
          {
               MethodB(new ObjectB(arg1), new ObjectC(arg1));
          }
          else
          {
               MethodC(new ObjectD(arg1), new ObjectE(arg1));
          }
     }
}

我正在尝试编写一个单元测试来测试对methodB或methodC的调用是否根据我的条件进行。这样的事情是如何实现的呢?

那么,为什么你不能简单地模仿这种方法呢

Mock<IObject> m = new Mock<IObject>();
m.Setup(x => s.MethodB(new ObjectB(arg1), new ObjectC(arg1)))
 .Callback(() => Console.WriteLine("MethodB Called"));
Mock m=new Mock();
m、 设置(x=>s.MethodB(新对象B(arg1),新对象C(arg1)))
.Callback(()=>Console.WriteLine(“调用了MethodB”);

因此,如果您的条件
如果(arg1.Something)
满足,那么将调用模拟的条件,您将知道您正在尝试模拟接口并验证此接口的实现

您可以使方法C和D虚拟化,并在模拟中使用实现

实施:

public class ObjectImplementation : IObject
{
    public void MethodA(ObjectA arg1)
    {
        if (arg1.Something)
        {
            MethodB(new ObjectB(arg1), new ObjectC(arg1));
        }
        else
        {
            MethodC(new ObjectD(arg1), new ObjectE(arg1));
        }
    }

    public virtual void MethodB(ObjectB arg1, ObjectC arg2)
    {

    }

    public virtual void MethodC(ObjectD arg1, ObjectE arg2)
    {

    }
}
[Fact]
public void Test_WhenSomethingIsTrue_MethodB_Invoked_WithObjects_B_And_C()
{
    // Arrange
    Mock<ObjectImplementation> mockObject = new Mock<ObjectImplementation>();
    ObjectA arg = new ObjectA();
    arg.Something = true;

    // Act
    mockObject.Object.MethodA(arg);

    // Assert
    mockObject.Verify(o => o.MethodB(It.Is<ObjectB>(b=> b.Arg == arg), It.Is<ObjectC>(c => c.Arg == arg)));
}

[Fact]
public void Test_WhenSomethingIsFalse_MethodC_Invoked_WithObjects_D_And_E()
{
    // Arrange
    Mock<ObjectImplementation> mockObject = new Mock<ObjectImplementation>();
    ObjectA arg = new ObjectA();
    arg.Something = false;

    // Act
    mockObject.Object.MethodA(arg);

    // Assert
    mockObject.Verify(o => o.MethodC(It.Is<ObjectD>(d => d.Arg == arg), It.Is<ObjectE>(e => e.Arg == arg)));
}
测试:

public class ObjectImplementation : IObject
{
    public void MethodA(ObjectA arg1)
    {
        if (arg1.Something)
        {
            MethodB(new ObjectB(arg1), new ObjectC(arg1));
        }
        else
        {
            MethodC(new ObjectD(arg1), new ObjectE(arg1));
        }
    }

    public virtual void MethodB(ObjectB arg1, ObjectC arg2)
    {

    }

    public virtual void MethodC(ObjectD arg1, ObjectE arg2)
    {

    }
}
[Fact]
public void Test_WhenSomethingIsTrue_MethodB_Invoked_WithObjects_B_And_C()
{
    // Arrange
    Mock<ObjectImplementation> mockObject = new Mock<ObjectImplementation>();
    ObjectA arg = new ObjectA();
    arg.Something = true;

    // Act
    mockObject.Object.MethodA(arg);

    // Assert
    mockObject.Verify(o => o.MethodB(It.Is<ObjectB>(b=> b.Arg == arg), It.Is<ObjectC>(c => c.Arg == arg)));
}

[Fact]
public void Test_WhenSomethingIsFalse_MethodC_Invoked_WithObjects_D_And_E()
{
    // Arrange
    Mock<ObjectImplementation> mockObject = new Mock<ObjectImplementation>();
    ObjectA arg = new ObjectA();
    arg.Something = false;

    // Act
    mockObject.Object.MethodA(arg);

    // Assert
    mockObject.Verify(o => o.MethodC(It.Is<ObjectD>(d => d.Arg == arg), It.Is<ObjectE>(e => e.Arg == arg)));
}
[事实]
公共无效测试\u当使用对象\u B\u和\u C()调用某个ThingsTrue\u方法B\u时
{
//安排
Mock mockObject=new Mock();
ObjectA arg=新ObjectA();
arg.Something=真;
//表演
mockObject.Object.MethodA(arg);
//断言
验证(o=>o.MethodB(It.Is(b=>b.Arg==Arg),It.Is(c=>c.Arg==Arg));
}
[事实]
公共无效测试\u当使用对象\u D\u和\u E()调用某个thingsFalse\u方法时
{
//安排
Mock mockObject=new Mock();
ObjectA arg=新ObjectA();
arg.Something=错误;
//表演
mockObject.Object.MethodA(arg);
//断言
验证(o=>o.MethodC(It.Is(d=>d.Arg==Arg),It.Is(e=>e.Arg==Arg));
}

虽然公认的解决方案应该有效,但我强烈建议您不要进行此类测试。每个方法调用都会产生一些输出和一些副作用。所以,若并没有输出,也并没有副作用,那个么该方法就并没有任何作用。通过断言调用了哪个MethodB或MethodC,您不会检查MethodA的输出,也不会检查它的副作用。这样的测试很脆弱,因为它们只测试MethodA的一个可能实现,而不是它的实际功能。我所说的脆性是指:

假设您有以下IObject的实现

class ObjectImpl
{
    public void MethodA(ObjectA arg1)
    {
        if (arg1.Something)
        {
            MethodB(new ObjectB(arg1), new ObjectC(arg1));
        }
        else
        {
            MethodC(new ObjectD(arg1), new ObjectE(arg1));
        }
    }

    public void MethodB(ObjectB arg1, ObjectC arg2)
    {
        Console.WriteLine("Hi {0} and {1}", arg1, arg2);
    }

    public void MethodC(ObjectD arg1, ObjectE arg2)
    {
        Console.WriteLine("Bye {0} and {1}", arg1, arg2);
    }
}
因此,MethodA基本上只是向控制台打印“Hi”或“Bye”。然后,如果有人注意到MethodB和MethodC除了MethodA之外不会在任何地方使用,他可能会删除它们。注意MethodA仍然是一样的,所以除了test之外没有任何东西被破坏

class ObjectImpl
{
    // Everything works as before except broken build
    public void MethodA(ObjectA arg1)
    {
        if (arg1.Something)
        {
            Console.WriteLine("Hi {0} and {1}", new ObjectB(arg1), new ObjectC(arg1));
        }
        else
        {
            Console.WriteLine("Bye {0} and {1}", new ObjectD(arg1), new ObjectE(arg1));
        }
    }
}

似乎有关系,就是这样!谢谢我只是不喜欢我必须将方法虚拟化的事实,但这正是我想要的。我最终通过测试实现了可接受的解决方案,以检查输入和输出参数是否符合预期。尽管如此,他们不会测试MethodB中可能发生的所有事情,但是已经有了针对该函数的单元测试。