测试UWP蓝牙应用程序

时间:2017-03-30 19:29:26

标签: c# windows unit-testing testing uwp

我正在尝试为使用Windows.Devices.Bluetooth.BluetoothLEDevice的Windows 10 UWP应用程序开发一些测试。我有一个普通的类,它是我的应用程序的一部分,它有一个私有的BluetoothLEDevice类型字段。

class MyDevice
{
    private Windows.Devices.Bluetooth.BluetoothLEDevice BluetoothLEDevice;

    public string SomeProperty { get; set; }

    public MyDevice(Windows.Devices.Bluetooth.BluetoothLEDevice bluetoothLEDevice)
    {
        BluetoothLEDevice = bluetoothLEDevice;

        var characteristic = BluetoothLEDevice.GetGattService(...)
            .GetCharacteristics(...)
            .First();

        characteristic.ValueChanged += OnValueChanged;
    } 

    // TODO: Write tests for this method
    private OnValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
    {
        string message = Encoding.ASCII.GetString(args.CharacteristicValue.ToArray());

        // Parse `message`

        SomeProperty = parsed;
    }

    ...
}

所述课程的方法使用bluetoothLEDevice的事件和方法,有些是私人的,有些是公开的。如何测试MyDevice的公共方法?

我尝试了类似的东西,我认为可以工作,但我可以看到它将需要数百行代码和相当多的额外类,因为我需要实现很多在FakeBluetoothLEDevice中的东西,以便它正常工作。

我改为MyDevice以接受包装器,然后创建包装器的两个实现。一个用于测试,另一个用于实际使用。

class MyDevice
{
    private MyApp.IBluetoothLEDeviceWrapper bluetoothLEDevice;
}

然后在我的测试中我使用假的。

private void ValueChangedEventDataParsingTest()
{
    var device = new FakeBluetoothLEDevice();

    var myDevice = new MyDevice(device);

    device.InvokeValueChanged("this is the value for a fake ValueChangedEvent");

    Assert.Equals(probe.SomeProperty, "expected");
}

是否有任何框架(可用于UWP)可以帮助我实现我想要的目标?或者甚至是一种更好的方法可以为我节省一些痛苦?

1 个答案:

答案 0 :(得分:1)

而不是专注于实现问题,重点关注您希望抽象显示的功能。使用您的简化示例,我能够使用一些重构来复制它,以便只与所需的功能进行交互。

[TestClass]
public class DeviceTests {
    [TestMethod]
    public void _ValueChangedEventDataParsingTest() {
        //Arrange
        var message = "message";
        var expected = "expected";
        var device = new FakeBluetoothLEDevice(message, expected);
        var sut = new MyDevice(device);

        //Act
        device.InvokeValueChanged(message);

        //Assert
        Assert.AreEqual(expected, sut.SomeProperty);
    }

    public interface IBlueToothService {
        Action<string> ValueChangedHandler { get; set; }
    }

    public class FakeBluetoothLEDevice : IBlueToothService {
        private string message;
        private string parsed;

        public FakeBluetoothLEDevice(string message, string expected) {
            this.message = message;
            this.parsed = expected;
        }
        public Action<string> ValueChangedHandler { get; set; }

        public void InvokeValueChanged(string p) {
            var handler = ValueChangedHandler ?? delegate { };
            if (p == message) {
                ValueChangedHandler(parsed);
            }
        }
    }

    public class MyDevice {
        private IBlueToothService device;

        public string SomeProperty { get; set; }

        public MyDevice(IBlueToothService device) {
            this.device = device;
            device.ValueChangedHandler = handler;
        }

        private void handler(string parsedValue) {
            SomeProperty = parsedValue;
        }
    }
}

使用关注点分离并将实施问题的重大举措置于实际实施背后。它极大地简化了这种功能的消费者。

如果关注的是测试解析功能,那么也将其抽象为自己的关注点。不要让课程超出他们的需要(SRP)

private OnValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args) {
    string message = Encoding.ASCII.GetString(args.CharacteristicValue.ToArray());

    // Parse `message`
    var parsed = parsingServce.Parse(message);

    SomeProperty = parsed;
}

这样,解析服务实现只需要针对ts核心功能进行测试。

但是从抽象的角度来看,在测试更高级别的功能时,不需要将解析器作为依赖项。

我建议检查当前的设计并将其重构为更加坚固。