我正在尝试为使用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)可以帮助我实现我想要的目标?或者甚至是一种更好的方法可以为我节省一些痛苦?
答案 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核心功能进行测试。
但是从抽象的角度来看,在测试更高级别的功能时,不需要将解析器作为依赖项。
我建议检查当前的设计并将其重构为更加坚固。