Upcasting to interfaces on Moq not working

236 views Asked by At

I'm using the moq for my tests. I upcast the object to its interface and found a problem.

Below are tests which show the problem.

  • OBJECTS

    public interface IVehicle { string Model { get; } }
    public interface ICar : IVehicle { }
    public class Golf : ICar
    {
        public Golf(string model)
        {
            this.Model = model;
        }
    
        public string Model { get; private set; }
    }
    
  • TEST FAIL

    [TestMethod]
    public void InheritanceInterface_Test_WithMoq()
    {
        string golfmodel = "gti";
        var gti = new Moq.Mock<Golf>(golfmodel).Object;
        var safeVehicle = gti as IVehicle;
        var vehicle = (IVehicle)gti;
        var safeCar = gti as ICar;
        var car = (ICar)gti;
    
        Assert.AreEqual(golfmodel, gti.Model, string.Format(" Model:{0} | Golf Model:{1}", golfmodel, gti.Model));
        Assert.AreEqual(gti.Model, safeVehicle.Model, string.Format("Golf Model:{0} | Vehicle Model:{1}", gti.Model, safeVehicle.Model));
        Assert.AreEqual(gti.Model, vehicle.Model, string.Format("Golf Model:{0} | Vehicle Model:{1}", gti.Model, vehicle.Model));
        Assert.AreEqual(gti.Model, safeCar.Model, string.Format("Golf Model:{0} | Carro Model:{1}", gti.Model, safeCar.Model));
        Assert.AreEqual(gti.Model, car.Model, string.Format("Golf Model:{0} | Carro Model:{1}", gti.Model, car.Model));
    }
    
  • TEST PASS

    [TestMethod]
    public void InheritanceInterface_Test()
    {
        string golfmodel = "gti";
        var gti = new Golf(golfmodel);
        var vehicle = (IVehicle)gti;
        var car = (ICar)gti;
    
        Assert.AreEqual(golfmodel, gti.Model, string.Format(" Model:{0} | Golf Model:{1}", golfmodel, gti.Model));
        Assert.AreEqual(gti.Model, vehicle.Model, string.Format("Golf Model:{0} | Vehicle Model:{1}", gti.Model, vehicle.Model));
        Assert.AreEqual(gti.Model, car.Model, string.Format("Golf Model:{0} | Carro Model:{1}", gti.Model, car.Model));
    }
    

How can I change it so that when I cast my Mock<Golf>.Object to one of its interfaces I can still access the Model property?

1

There are 1 answers

0
forsvarir On BEST ANSWER

By default, when you Mock a concrete type, Moq is not going to call down to methods that are virtual, or implementing interfaces. It will only only do so if you tell it that it can call the base implementation, otherwise it will assume you're going to Setup those methods if you need to call them. If you change your test to the following it will work:

[TestMethod]
public void InheritanceInterface_Test_WithMoq()
{
    string golfmodel = "gti";
    var golfMock = new Moq.Mock<Golf>(golfmodel);

    golfMock.CallBase = true;  // Tell the mock to call base methods

    var gti = golfMock.Object;
    var safeVehicle = gti as IVehicle;
    var vehicle = (IVehicle)gti;
    var safeCar = gti as ICar;
    var car = (ICar)gti;

    Assert.AreEqual(golfmodel, gti.Model, string.Format(" Model:{0} | Golf Model:{1}", golfmodel, gti.Model));
    Assert.AreEqual(gti.Model, safeVehicle.Model, string.Format("Golf Model:{0} | Vehicle Model:{1}", gti.Model, safeVehicle.Model));
    Assert.AreEqual(gti.Model, vehicle.Model, string.Format("Golf Model:{0} | Vehicle Model:{1}", gti.Model, vehicle.Model));
    Assert.AreEqual(gti.Model, safeCar.Model, string.Format("Golf Model:{0} | Carro Model:{1}", gti.Model, safeCar.Model));
    Assert.AreEqual(gti.Model, car.Model, string.Format("Golf Model:{0} | Carro Model:{1}", gti.Model, car.Model));
}