Skip to content

Pattern 11: Testing Without Hardware

Mock SDK

internal interface ISdkClient
{
    Task<bool> OpenDoor(uint address, uint doorId, CancellationToken cancellationToken);
    Task<DeviceInfo> GetDeviceInfo(uint address, CancellationToken cancellationToken);
}

internal sealed class RealSdkClient : ISdkClient
{
    // actual SDK implementation
}

internal sealed class MockSdkClient : ISdkClient
{
    public Task<bool> OpenDoor(uint address, uint doorId, CancellationToken cancellationToken)
    {
        Console.WriteLine($"Mock: Opening door {doorId} on device {address}");
        return Task.FromResult(true);
    }

    public Task<DeviceInfo> GetDeviceInfo(uint address, CancellationToken cancellationToken)
    {
        return Task.FromResult(new DeviceInfo
        {
            Model = "MockDevice",
            FirmwareVersion = "1.0.0"
        });
    }
}

DI Configuration

// In appsettings.Development.json
{
  "Adapter": {
    "UseMockSdk": true
  }
}

// In DI registration
if (configuration.GetValue<bool>("Adapter:UseMockSdk"))
    services.AddSingleton<ISdkClient, MockSdkClient>();
else
    services.AddSingleton<ISdkClient, RealSdkClient>();

Simulating Events

internal sealed class MockSdkClient : ISdkClient
{
    private readonly Timer _eventTimer;
    public event EventHandler<DeviceEvent>? OnEvent;

    public MockSdkClient()
    {
        // simulate events every 5 seconds
        _eventTimer = new Timer(_ => SimulateEvent(), null,
            TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5));
    }

    private void SimulateEvent()
    {
        var evt = new DeviceEvent(
            Code: 0x1000, // Access Granted
            Timestamp: DateTime.UtcNow,
            DoorId: 1,
            PersonId: 12345,
            CredentialId: 67890,
            RawData: Array.Empty<byte>()
        );

        OnEvent?.Invoke(this, evt);
    }
}

Integration Tests

[Fact]
public async Task OpenDoor_SendsCorrectCommand()
{
    // Arrange
    var mockSdk = new MockSdkClient();
    var protocol = new Protocol(mockSdk, ...);

    // Act
    var result = await protocol.OpenDoor(doorId: 1, CancellationToken.None);

    // Assert
    Assert.True(result);
    Assert.Equal(1, mockSdk.CommandsSent.Count);
    Assert.Equal("OpenDoor", mockSdk.CommandsSent[0].Type);
}

Benefits of Mocking

  • Fast iteration - no hardware setup required
  • CI/CD compatible - tests run in pipeline
  • Edge case testing - simulate rare conditions
  • Parallel development - work before hardware arrives
  • Regression testing - automated test suite