Moq - 在同一个类中调用两个函数,一个是真实的,一个是嘲弄的

use*_*891 2 c# unit-testing moq

我有一段代码,我可能无法改变.理想情况下,我会将Publish方法移动到另一个类中.嘲弄将成为一个微不足道的操作,我会很好.这是一个简化的例子.

public class Entity
{
  private IController _controller;

  // Omitted: Constructor where IController is assigned

  public virtual int Process()
  {
    return Publish(_controller.DoSomeStuff());
  }

  public virtual int Publish(int val)
  {
    Console.WriteLine(val);  // This is actually a call to an external system.
    return val;
  }
}
Run Code Online (Sandbox Code Playgroud)

我想要做的是调用真正的Process方法和模拟的Publish方法._controller的值也将被模拟.

我尝试使用moq并做:

var mock = new Mock<IController>();
mock.Setup(m => m.DoSomeStuff()).Returns(11);

var mock2 = new Mock<Entity_Accessor>();
mock2.CallBase = true;
mock2.Setup(a => a.Publish(It.IsAny<int>())).Returns(999);
mock2.Object._controller = mock.Object;

int result = mock2.Object.Process();
Assert.AreEqual(999, result);
Run Code Online (Sandbox Code Playgroud)

当我运行此测试时,返回值11而不是999.如果我删除mock2.CallBase = true,则整个类被模拟,它返回每个函数的默认值.

在保留Process的原始实现的同时,是否可以在这种情况下仅模拟Publish方法?

是否有可能通过不同于Typemock或Justmock的不同模拟框架来实现上述目标(不确定客户是否会为模拟工具的多个副本买单)?

谢谢!

Cha*_*ert 5

如果您正在尝试测试该Process方法的功能,则不应使用模拟,您应该使用该类的实际实例IController并模拟该接口并模拟DoSomeStuff以返回预期值,然后验证是否Process正确处理该值.

如果你只是想嘲笑你的Entity课程,那么就没有必要嘲笑你IController.只需在Entity类上嘲笑你的方法,让它们返回你想要的东西.

更新:

您不应该模拟正在测试的类的一部分.也许你应该传递对外部系统的引用,以便你可以嘲笑它.除非Publish中的代码是直接调用外部系统的责任方.这将是推荐的方法.但是,如果发布方法负责直接调用外部系统,那么你就需要采取不同的方法,做集成测试来代替.

与单元测试相比,集成测试通常不会快速运行,并且它要求所有系统交互都启动并运行.这也意味着在大多数情况下你不会嘲笑事物.这是野兽的本质,我强烈建议你不要绕过这样的过程.