Sheinar
Sheinar

Reputation: 402

AutoFixture AutoMoq not use my mocks for properties

I have an abstract class that I want to test. There is an abstract property in this class for my DAO, which I define in inherited classes.

public abstract class DeviceGroupManagerBase<TDeviceGroup> where TDeviceGroup : DeviceGroup 
{
    protected abstract IDeviceGroupDao<TDeviceGroup> DeviceGroupDao { get; }

    public TDeviceGroup UpdateDeviceIndexes(Device device)
    {
        return DeviceGroupDao.GetDeviceGroup(device.Group.Id);
    }
}

I want to test the Updatedeviceindexes method so I'm trying to mock a property called DeviceGroupDao.

[TestFixture]
[Category("Unit")]
public class DeviceGroupManagerBaseTests
{
    private IFixture fixture;
    private Mock<DeviceGroupManagerBase<DeviceGroup>> subject;
    private Mock<IDeviceGroupDao<DeviceGroup>> deviceGroupDaoMock;
    private DeviceGroupManagerBase<DeviceGroup> Manager => subject.Object;

    [TestFixtureSetUp]
    public void Init()
    {
        fixture = new Fixture().Customize(new AutoMoqCustomization());
        deviceGroupDaoMock = fixture.Freeze<Mock<IDeviceGroupDao<DeviceGroup>>>();
        subject = fixture.Freeze<Mock<DeviceGroupManagerBase<DeviceGroup>>>();
    }

    [Test]
    public void TestUpdateDeviceIndexes()
    {
        var device = fixture.Create<Device>();
        var deviceGroup = fixture.Create<DeviceGroup>();

        deviceGroupDaoMock.Setup(x => x.GetDeviceGroup(It.IsAny<int>())).Returns(deviceGroup);

        var result = Manager.UpdateDeviceIndexes(device);
        // The resultDeviceGroup will not be contain a previously defined object

        Assert.AreEqual(deviceGroup.Id, result.Id);
    }
}

I also tried to add registration for my device object in this way:

fixture.Register(() => deviceGroup);

But I'm still getting a new object.

How can I mock IDeviceGroupDao<TDeviceGroup>?

Upvotes: 3

Views: 1549

Answers (2)

Mark Seemann
Mark Seemann

Reputation: 233125

Since DeviceGroupManagerBase is an abstract base class, you'll need a SUT Double. It's easiest to do if you make the DeviceGroupDao property public:

public abstract class DeviceGroupManagerBase<TDeviceGroup> where TDeviceGroup : DeviceGroup
{
    public abstract IDeviceGroupDao<TDeviceGroup> DeviceGroupDao { get; }

    public TDeviceGroup UpdateDeviceIndexes(Device device)
    {
        return DeviceGroupDao.GetDeviceGroup(device.Group.Id);
    }
}

Otherwise, you'll need to use Moq's API for defining and overriding protected members, which is possible, but more work.

Then you'll need to override subject's DeviceGroupDao property:

subject.SetupGet(x => x.DeviceGroupDao).Returns(deviceGroupDaoMock.Object);

Here's the full test:

[TestFixture]
[Category("Unit")]
public class DeviceGroupManagerBaseTests
{
    private IFixture fixture;
    private Mock<DeviceGroupManagerBase<DeviceGroup>> subject;
    private Mock<IDeviceGroupDao<DeviceGroup>> deviceGroupDaoMock;
    private DeviceGroupManagerBase<DeviceGroup> Manager => subject.Object;

    [OneTimeSetUp]
    public void Init()
    {
        fixture = new Fixture().Customize(new AutoMoqCustomization());
        deviceGroupDaoMock = fixture.Freeze<Mock<IDeviceGroupDao<DeviceGroup>>>();
        subject = fixture.Freeze<Mock<DeviceGroupManagerBase<DeviceGroup>>>();
        subject.SetupGet(x => x.DeviceGroupDao).Returns(deviceGroupDaoMock.Object);
    }

    [Test]
    public void TestUpdateDeviceIndexes()
    {
        var device = fixture.Create<Device>();
        var deviceGroup = fixture.Create<DeviceGroup>();

        deviceGroupDaoMock.Setup(x => x.GetDeviceGroup(It.IsAny<int>())).Returns(deviceGroup);

        var result = Manager.UpdateDeviceIndexes(device);

        Assert.AreEqual(deviceGroup.Id, result.Id);
    }
}

This now passes on my machine.

Upvotes: 2

Nkosi
Nkosi

Reputation: 247018

Because the DeviceGroupDao is protected you will need to find a way to access it externally. Create a stub that would allow you set it value.

public class DeviceGroupManagerBaseStub<TDeviceGroup> 
    : DeviceGroupManagerBase<TDeviceGroup> where TDeviceGroup : DeviceGroup {

    private IDeviceGroupDao<TDeviceGroup> deviceGroupDao;

    public DeviceGroupManagerBaseStub(IDeviceGroupDao<TDeviceGroup> deviceGroupDao) {
        this.deviceGroupDao = deviceGroupDao;
    }

    protected override IDeviceGroupDao<TDeviceGroup> DeviceGroupDao {
        get {
            return deviceGroupDao;
        }
    }
}

You can then mock IDeviceGroupDao<TDeviceGroup> and inject it into the stub for your test.

Upvotes: 2

Related Questions