AutoFixture AutoMoq 不使用我的属性模拟

AutoFixture AutoMoq not use my mocks for properties

我有一个要测试的摘要 class。我的 DAO 在这个 class 中有一个抽象 属性,我在 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);
    }
}

我想测试 Updatedeviceindexes 方法,所以我试图模拟一个名为 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);
    }
}

我也试过用这种方式为我的设备对象添加注册:

fixture.Register(() => deviceGroup);

但我仍然得到了一个新对象。

如何模拟 IDeviceGroupDao<TDeviceGroup>

因为 DeviceGroupDao 受到保护,您需要找到一种从外部访问它的方法。创建一个允许您为其设置值的存根。

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

然后您可以模拟 IDeviceGroupDao<TDeviceGroup> 并将其注入存根以进行测试。

由于 DeviceGroupManagerBase 是一个抽象基础 class,您将需要一个 SUT Double。如果使 DeviceGroupDao 属性 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);
    }
}

否则,您将需要使用 Moq 的 API 来定义和覆盖 protected 成员,这是可能的,但需要更多工作。

然后你需要覆盖 subjectDeviceGroupDao 属性:

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

完整测试如下:

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

这现在在我的机器上通过了。