如何使用未传递给真实对象的模拟

How to use mock which is not passed to real object

我有如下所示的服务 CarTankService。它有我想测试的 Add 方法。更详细地说,我想检查是否会达到 AddTank (inside Add)

public class CarTankService : ICarTankService
{
    private readonly ITankQuery _tankQuery;
    private readonly CarClient _carClient;

    public CarTankService(ITankQuery tankQuery)
    {
        _tankQuery = tankQuery;
        _carClient = new CarClient();
    }

    public ObservableCollection<CarTank> GetTanks() => _carClient.Tanks;

    public void GenerateNewList() => _carClient.GenerateNewTanksList();

    public virtual void Add(CarTank tank)
    {
        if (_tankQuery.isExist(tank.Number)) throw new OwnException()

        _carClient.AddTank(tank);
    }

    public virtual void Remove(CarTank tank) => _carClient.RemoveCarTank(tank);
}

这是我的测试方法class:

[TestFixture]
class CarTankServiceTests
{
    private Mock<ITankQuery> TankQuery { get; set; }
    private ICarTankService CarTankService { get; set; }
    private Mock<CarClient> CarClient { get; set; }

    [SetUp]
    public void SetUp()
    {
        TankQuery = new Mock<ITankQuery>();
        CarClient = new Mock<CarClient>();
        CarTankService = new CarTankService(TankQuery.Object);
    }

    [Test]
    public void Add_NotExistReferenceNumber_AddTankReached()
    {
        TankQuery.Setup(uow => uow.isExist(It.IsAny<int>())).Returns(false);

        CarTankService.Add(new CarTank());

        CarClient.Verify(uow => uow.AddTank(It.IsAny<ClientTank>()),Times.Once);
    }
}

CarClient.Verify 对于 AddTank 总是显示它在测试中是 0 occurence,在这种情况下是不正确的。我不确定,但我认为这是因为 CarClient 模型 class 因为它没有直接注入我的服务,它总是显示 0。我对吗?有什么选项可以测试吗?

如果您模拟 CarClient,则必须设置要在测试中使用的所有方法(此处 AddTank)。在您的代码中,我们有两个 CarClient 实例,一个在您的测试中被模拟,另一个在您的 CarTankService 的构造函数中初始化。因此,您在验证模拟的情况时调用了后一种情况。

如果将CarClient转换为接口注入,解决方法如下:

[TestFixture]
class CarTankServiceTests
{
    private Mock<ITankQuery> TankQuery { get; set; }
    private ICarTankService CarTankService { get; set; }
    private Mock<CarClient> CarClient { get; set; }

    [SetUp]
    public void SetUp()
    {
        TankQuery = new Mock<ITankQuery>();
        CarClient = new Mock<CarClient>();
        CarTankService = new CarTankService(TankQuery.Object);
    }

    [Test]
    public void Add_NotExistReferenceNumber_AddTankReached()
    {
        TankQuery.Setup(uow => uow.isExist(It.IsAny<int>())).Returns(false);

        CarTankService.Add(new CarTank());

        CarClient.Setup(a=>a.AddTank(/*write you loginc*/));
        CarClient.Verify(uow => uow.AddTank(It.IsAny<ClientTank>()),Times.Once);
    }
}

这里有更多的解释:

当您在测试中编写 CarTankService = new CarTankService(TankQuery.Object); 时,它会在您的 class (_carClient = new CarClient();) 上创建一个新实例,因此 class 有自己的实例,而测试 class 也有它自己的 (CarClient = new Mock<CarClient>();),这是被嘲笑的。这行代码 CarTankService.Add(new CarTank()); 将坦克添加到 class 的实例,而在您的测试中,您正在验证没有坦克 (CarClient.Verify(uow => uow.AddTank(It.IsAny<ClientTank>()),Times.Once);) 的测试实例 class .