对使用 RegistryManager C# Azure IoTHub 的 class 进行单元测试
Unit Testing a class that uses RegistryManager C# Azure IoTHub
我正在尝试测试使用 RegistryManager
与 IoThub 通信的 class。
我面临的问题是,当创建一个继承自 RegistryManager
的模拟 class 时,我能够覆盖除 ExportRegistryAsync
之外的所有方法。我在覆盖下得到一条红线,如果我删除覆盖语句,我在构建项目时会收到此错误:
Error 4 'MockObjects.MockRegistryManager' does not implement inherited abstract member '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
的 class?
非常感谢任何帮助。
给你当前版本class待测试
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
的问题。您需要对要使用的服务进行抽象,以便您可以 mock/fake 对它们进行测试而无需使用真实的服务。
类似于
public interface IRegistryManager {
Task<Device> GetDeviceAsync(string deviceId);
}
这将允许您像这样重构您的 class
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
class 完全可测试。您会注意到,除了注册表管理器字段的类型之外,不需要更改任何其他内容。不错
您现在可以根据需要使用测试框架制作一个假的 RegistryManager
或模拟一个。
当您需要在您的生产代码中进行实际调用时,您只需将真实的东西包装在您的界面中并将其传递到您的 Registry
class
public class ActualRegistryManager : IRegistryManager {
private readonly RegistryManager _registryManager
public ActualRegistryManager (RegistryManager manager) {
_registryManager = manager;
}
public Task<Device> GetDeviceAsync(string deviceId) {
return _registryManager.GetDeviceAsync(deviceId);
}
}
这种方法的好处之一是,您现在只需公开真正需要依赖 classes 的功能。
使用 Moq
和 FluentAssertions
我能够通过以下测试
模拟并测试 Registry
class
[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);
}
希望对您有所帮助。
我正在尝试测试使用 RegistryManager
与 IoThub 通信的 class。
我面临的问题是,当创建一个继承自 RegistryManager
的模拟 class 时,我能够覆盖除 ExportRegistryAsync
之外的所有方法。我在覆盖下得到一条红线,如果我删除覆盖语句,我在构建项目时会收到此错误:
Error 4 'MockObjects.MockRegistryManager' does not implement inherited abstract member '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
的 class?
非常感谢任何帮助。
给你当前版本class待测试
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
的问题。您需要对要使用的服务进行抽象,以便您可以 mock/fake 对它们进行测试而无需使用真实的服务。
类似于
public interface IRegistryManager {
Task<Device> GetDeviceAsync(string deviceId);
}
这将允许您像这样重构您的 class
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
class 完全可测试。您会注意到,除了注册表管理器字段的类型之外,不需要更改任何其他内容。不错
您现在可以根据需要使用测试框架制作一个假的 RegistryManager
或模拟一个。
当您需要在您的生产代码中进行实际调用时,您只需将真实的东西包装在您的界面中并将其传递到您的 Registry
class
public class ActualRegistryManager : IRegistryManager {
private readonly RegistryManager _registryManager
public ActualRegistryManager (RegistryManager manager) {
_registryManager = manager;
}
public Task<Device> GetDeviceAsync(string deviceId) {
return _registryManager.GetDeviceAsync(deviceId);
}
}
这种方法的好处之一是,您现在只需公开真正需要依赖 classes 的功能。
使用 Moq
和 FluentAssertions
我能够通过以下测试
Registry
class
[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);
}
希望对您有所帮助。