2

我正在尝试测试用于RegistryManager与 IoThub 通信的类。

我面临的问题是,当创建一个继承自的模拟类时,RegistryManager我能够覆盖除ExportRegistryAsync. 我在覆盖下得到一条红线,如果我删除覆盖语句,我在构建项目时会收到​​此错误:

错误 4 'MockObjects.MockRegistryManager' 没有实现继承的抽象成员 'Microsoft.Azure.Devices.RegistryManager.ExportRegistryAsync(string, string)' Tests\MockObjects\MockRegistryManager.cs 9 18

代码:

public class MockRegistryManager : RegistryManager
{
    private static List<Device> _devices;

    public MockRegistryManager()
    {
        _devices = new List<Device>();
    }

    public override Task OpenAsync()
    {
        throw new NotImplementedException();
    }


    ...


    internal override Task ExportRegistryAsync(string storageAccountConnectionString, string containerName)
    {
        throw new NotImplementedException();
    }

    internal override Task ExportRegistryAsync(string storageAccountConnectionString, string containerName, CancellationToken cancellationToken)
    {
        throw new NotImplementedException();
    }

}

有没有更好的方法来测试使用的类RegistryManager

任何帮助将不胜感激。

4

1 回答 1

2

给定您要测试的类的当前版本

public class Registry {
    private readonly RegistryManager _registryManager;

    public Registry(RegistryManager rm) {
        _registryManager = rm;
    }

    public async Task<string> GetDeviceKey(string deviceId = null) {
        if (deviceId == null) {
            throw new Exception("Todo replace");
        }
        var device = await _registryManager.GetDeviceAsync(deviceId);
        if (device == null) {
            throw new Exception("TODO replace");
        }
        return device.Authentication.SymmetricKey.PrimaryKey;
    }
}

如果您想对此进行测试,那么您将遇到RegistryManager. 您需要对要使用的服务进行抽象,以便您可以模拟/伪造它们以进行测试,而无需使用真实的东西。

就像是

public interface IRegistryManager {
    Task<Device> GetDeviceAsync(string deviceId);
}

然后,这将允许您像这样重构您的类

public class Registry {
    private readonly IRegistryManager _registryManager;

    public Registry(IRegistryManager rm) {
        _registryManager = rm;
    }

    public async Task<string> GetDeviceKey(string deviceId = null) {
        if (deviceId == null) {
            throw new Exception("Todo replace");
        }
        var device = await _registryManager.GetDeviceAsync(deviceId);
        if (device == null) {
            throw new Exception("TODO replace");
        }
        return device.Authentication.SymmetricKey.PrimaryKey;
    }
}

现在可以让您的Registry课程完全可测试。您会注意到,除了注册表管理器字段的类型之外,不需要更改任何其他内容。好的。

您现在可以RegistryManager根据需要使用测试框架制作一个假的或模拟的。

当您需要在生产代码中进行实际调用时,您只需将真实的东西包装在您的界面中并将其传递给您的Registry

public class ActualRegistryManager : IRegistryManager {
    private readonly RegistryManager _registryManager

    public ActualRegistryManager (RegistryManager manager) {
        _registryManager = manager;
    }

    public Task<Device> GetDeviceAsync(string deviceId) {
        return _registryManager.GetDeviceAsync(deviceId);
    }
}

这种方法的好处之一是您现在只需要向依赖类公开您真正需要的功能。

使用Moq并且FluentAssertions我能够Registry通过以下测试模拟和测试课程

[TestMethod]
public async Task Registry_Should_Return_DeviceKey() {
    //Arrange
    var expectedPrimaryKey = Guid.NewGuid().ToString();
    var deviceId = Guid.NewGuid().ToString();
    var fakeDevice = new Device(deviceId) {
        Authentication = new AuthenticationMechanism {
            SymmetricKey = new SymmetricKey {
                 PrimaryKey = expectedPrimaryKey
            }
        }
    };
    var registryManagerMock = new Mock<IRegistryManager>();
    registryManagerMock.Setup(m => m.GetDeviceAsync(deviceId))
        .ReturnsAsync(fakeDevice);
    var registry = new Registry(registryManagerMock.Object);

    //Act                
    var deviceKey = await registry.GetDeviceKey(deviceId);

    //Assert
    deviceKey.Should().BeEquivalentTo(expectedPrimaryKey);
}

希望这可以帮助。

于 2016-04-15T16:22:47.557 回答