使用 Moq (C#) 监视对象

Spy an object with Moq (C#)

我正在构建一个 .NET Core 应用程序,我想使用 Moq 监视实例化对象,但我还没有找到实现它的方法。

基本上,我需要的是here被描述为间谍的东西。

我发现我可以使用以下方式调用 class Foo 的基本 class 方法:

 var mock = new Mock<Foo>();
 mock.CallBase = true;

我的问题是 Moq 将创建一个 Foo 的新实例,而我需要的是使用一个已经实例化的对象并在调用对象的实际函数时仅模拟真实对象的一种方法。

这是我要监视的对象的结构。

    public class Foo:Boo
    {
       Foo(Propeties props):base(props){}

       public Baz MockMe(){...}

       public Daz DoNotMockMe(){ 
           return DoSomethingWith(Properties);
        }
    }

Moq 不支持现有对象。但是,它确实接受参数来调用构造函数。当我们使用像装饰器模式这样的变通方法时,这可能是解决方案。

请注意在使用(现有)实例时有一个警告:类 使用您的模拟实例 (carMock.Object) 使用您配置的设置。但是,被测试的 class 本身 (actualCar) 并不知道它正在被装饰,因此 而不是 ,如下例所示。

public class Car : ICar
{
    public virtual string Manufacturer { get; set; }
    public virtual string Model { get; set;}
    public virtual string Name => $"{Manufacturer} {Model}";
}

public class CarTestHelper : ICar
{
    private readonly ICar _innerCar;

    public CarTestHelper(ICar car)
    {
        _innerCar = car;
    }

    // These properties use the existing instance passed in the constructor
    public string Manufacturer { get => _innerCar.Manufacturer; set => _innerCar.Manufacturer = value; }
    public virtual string Model { get => _innerCar.Model; set => _innerCar.Model = value; } // Virtual property can be mocked using Moq
    public string Name => _innerCar.Name; // Does NOT use mocked 'Model'.
}    

[TestFixture]
public class CarTests
{
    [Test]
    public void NameIsManufacturerWithModel()
    {
        var actualCar = new Car
        {
            Manufacturer = "Nissan",
            Model = "100NX"
        };

        var carMock = new Mock<CarTestHelper>(actualCar)  // Pass the decorated car as constructor parameter
        {
            CallBase = true
        };

        carMock.SetupGet(c => c.Model).Returns("200SX");

        Assert.AreEqual("Nissan 200SX", carMock.Object.Name);  // Will fail as the car will not used the mocked value.
    }
}

Visual studio 有一个很好的快速修复,可以在您从 ICar 继承并将其作为构造函数参数时自动实现装饰器模式。