C#Moq拦截方法调用

时间:2018-04-26 09:39:49

标签: 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 void MethodA(ObjectA arg1)
     {
          if(arg1.Something)
          {
               MethodB(new ObjectB(arg1), new ObjectC(arg1));
          }
          else
          {
               MethodC(new ObjectD(arg1), new ObjectE(arg1));
          }
     }
}

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

3 个答案:

答案 0 :(得分:2)

您正在尝试模拟接口并验证此接口的实现。

您可以将方法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)));
}

答案 1 :(得分:0)

为什么你不能简单地假装那个方法存根

Mock<IObject> m = new Mock<IObject>();
m.Setup(x => s.MethodB(new ObjectB(arg1), new ObjectC(arg1)))
 .Callback(() => Console.WriteLine("MethodB Called"));

因此,如果您的条件if(arg1.Something)满足,那么将会调用被模拟的条件,您将知道

答案 2 :(得分:0)

虽然接受的解决方案应该有效,但我强烈建议您不要进行此类测试。每个方法调用都会产生一些输出和一些副作用。因此,如果没有输出且没有副作用,那么方法根本不做任何事情。通过声明调用哪个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只是打印&#34;嗨&#34;或者&#34;再见&#34;到控制台。然后,如果有人会注意到MethodB和MethodC在MethodA之外的任何地方都没有使用过,他可能会删除它们。请注意,MethodA仍然是相同的,因此除了测试之外什么都不会被破坏。

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