问题
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