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中可能发生的所有事情,但是已经有了针对该函数的单元测试。