How to use mock which is not passed to real object

瘦欲@ 提交于 2020-06-27 04:02:57

问题


I have service CarTankService as shown below. It has Add method which i want to test. To be more detailed i would like to check whether AddTank (inside Add) will be reached.

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

This is my test method 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 for AddTank always show it was 0 occurence in test, which in this case is not true. I am not sure but I think it's because CarClient model class because it's not injected directly insdie my service it always shows 0. AM i right? Is there any option to test it?


回答1:


If you mock your CarClient you have to setup all methods you want to use in your test (here AddTank). In you code we have two CarClient instances, one is mocked in your test and another is initialized in your constructor of CarTankService. So, you are calling the latter case while verifying the mocked one.

If you convert the CarClient to an interface and inject it, The solution is something like this:

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

Here is more explanation:

When you write CarTankService = new CarTankService(TankQuery.Object); in your test, it creates a new instance on your class (_carClient = new CarClient();), so the class has it's own instance, while the test class has it own too (CarClient = new Mock<CarClient>();) which is mocked. This line of code CarTankService.Add(new CarTank()); adds the tank to the instance of class, while in your test, you are verifying the instance of test class which has no tank (CarClient.Verify(uow => uow.AddTank(It.IsAny<ClientTank>()),Times.Once);).



来源:https://stackoverflow.com/questions/60916220/how-to-use-mock-which-is-not-passed-to-real-object

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!