2016-04-15 14 views
1

Ich versuche meine Klasse zu testen, die RegistryManager verwendet, um mit IoThub zu kommunizieren.Unit Testen einer Klasse, die RegistryManager verwendet C# Azure IoTHub

Das Problem, das mir gegenübersteht, ist, dass ich beim Erstellen einer Scheinklasse, die von RegistryManager erbt, alle Methoden mit Ausnahme von ExportRegistryAsync überschreiben kann. Ich erhalte eine rote Linie unter Überschreibung und wenn ich die Überschreibung Anweisung mir diesen Fehler entfernen, wenn ich das Projekt erstellen:

Fehler 4 ‚MockObjects.MockRegistryManager‘ nicht abstrakt Mitglied ‚Microsoft.Azure.Devices geerbt umzusetzen. RegistryManager.ExportRegistryAsync (string, string)‘Tests \ MockObjects \ MockRegistryManager.cs 9 18

Code:

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

} 

gibt es einen besseren Weg, um eine Klasse zu testen, die RegistryManager verwendet?

Jede Hilfe wird sehr geschätzt.

+0

was meinst du mit roter linie unter override? Kompilieren oder nicht, wenn Sie überschreiben? – Nitin

+0

können Sie die Methoden und Eigenschaften, die Sie verwenden möchten, in eine Schnittstelle abstrahieren, so dass Sie sich über eine enge Kopplung mit dem 'RegistryManager' lustig machen können. Du solltest nicht versuchen, eine Klasse zu verspotten, die du nicht besitzt. – Nkosi

+0

Können Sie ein Schnipsel der Klasse anzeigen, die den 'RegistryManager' verwendet oder davon abhängig ist. – Nkosi

Antwort

2

Sie aktuelle Version der Klasse geben

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

Wenn Sie dies testen wollen, dann werden Sie Probleme mit dem RegistryManager haben. Sie benötigen eine Abstraktion der Dienste, die Sie verwenden möchten, so dass Sie sie für das Testen vortäuschen/fälschen können, ohne das echte Ding verwenden zu müssen.

so etwas wie

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

Dies wird dann können Sie Ihre Klasse wie diese

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

Refactoring, die nun Ihre Registry Klasse ermöglicht vollständig überprüfbar zu sein. Sie werden feststellen, dass außer dem Typ des Registrierungs-Manager-Feldes nichts anderes geändert werden muss. nett.

Sie können jetzt eine gefälschte RegistryManager oder eine nachmachen mit Test-Frameworks nach Bedarf.

Wenn Sie die tatsächlichen Anrufe in Ihrem Produktionscode vornehmen müssen wickeln Sie nur die reale Sache in Ihrer Schnittstelle und geben Sie ihn in Ihre Registry Klasse

public class ActualRegistryManager : IRegistryManager { 
    private readonly RegistryManager _registryManager 

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

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

Eines der guten Dinge mit diesem Ansatz ist, dass Sie Jetzt müssen Sie nur noch die Funktionalität offenlegen, die Sie wirklich für abhängige Klassen benötigen.

Mit Moq und FluentAssertions konnte ich Mock-up und testen Sie die Registry Klasse mit dem folgenden Test

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

Hoffnung, das hilft.

+1

@Nikosi Danke! – Reginbald

+0

Kein Problem. froh, dass ich Helfen kann. – Nkosi

Verwandte Themen