【问题标题】:AutoFixture AutoMoq not use my mocks for propertiesAutoFixture AutoMoq 不使用我的属性模拟
【发布时间】:2017-11-10 09:28:21
【问题描述】:

我有一个要测试的抽象类。这个类中有一个抽象属性用于我的 DAO,我在继承的类中定义。

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&lt;TDeviceGroup&gt;

【问题讨论】:

    标签: c# unit-testing nunit moq autofixture


    【解决方案1】:

    由于DeviceGroupManagerBase 是一个抽象基类,您需要一个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);
        }
    }
    

    这现在在我的机器上传递。

    【讨论】:

      【解决方案2】:

      因为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&lt;TDeviceGroup&gt; 并将其注入存根中进行测试。

      【讨论】:

      • 如果设计完全锁定,此答案很有用。它很好地解决了属性为protected 的问题,同时保持测试类型安全。我认为,它还表明构造函数注入总体上会是一个更好的设计,因此使自己变得多余是这样做的另一个好处:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-09
      • 1970-01-01
      • 1970-01-01
      • 2022-12-22
      • 1970-01-01
      相关资源
      最近更新 更多