I have a Xamarin solution in VS2017, which implements a physical device a few times (over usb/serial and bluetooth) on Windows UWP and Android. These devices all implement IMyDevice, which defines a simple state machine that models MyDevice being connected or not, and measuring or not.
I test these implementations using Xunit, in their respective namespaces, and since they all implement IMyDevice, I get quite a few tests that are literally identical, and currently repeated 3 times. I will soon add more devices, and must find a way to prevent this repetition from getting completely out of hand.
To test my view models, I build an assembly in a separate, common namespace and include it in my various unit test projects, using:
AddTestAssembly(typeof(MyViewModel).GetTypeInfo().Assembly);
This works for view models because I don't need any platform specific types, but alas, I don't think I'll be able to pass a MyDevice implementation to an assembly that is already built!
A more feasible approach would be to use Xamarin's dependency service
DependencyService.Get<MyDevice>();
However, it seems conceptually wrong to me that my Serial/Bluetooth unit tests should require Xamarin forms. And I'm not sure I'd be done anyway because I'd still need to disambiguate my serial and Bluetooth device on windows.
Therefore I wrote it out long-hand. I was Using Xuint in two projects/namespaces like:
namespace Test.MyApp.UWP {
public class TestMyBluetoothDeviceUWP {
[Fact]
void DeviceDoesntSuck() {
Assert.False(new MyUWPBluetoothDevice().sucks());
}
}
public class TestMySerialDeviceUWP {
[Fact]
void DeviceDoesntSuck() {
Assert.False(new MyUWPSerialDevice().sucks());
}
}
}
namespace Test.MyApp.Droid{
public class TestMyDeviceDroid {
[Fact]
void DeviceDoesntSuck() {
Assert.False(new MyDeviceDroid().sucks());
}
}
}
The popular answer to questions similar to mine seems to be using a [Theory]
namespace Test.MyApp{
public class TestMyDevice {
[Theory]
[ClassData new MyUWPBluetoothDevice()]
[ClassData new MyUWPSerialDevice()]
[ClassData new MyDeviceDroid()]
void DeviceDoesntSuck(IMyDevice myDevice) {
Assert.False(myDevice.sucks());
}
}
}
this helps with devices defined within the same namespace, however it does not help with the repetition across test projects (namespaces)
so far the best solution I can think of (which is not that great) is to define the tests statically, and wrap them in callers in the test projects
namespace Test.MyApp{
public static class TestMyDevice {
static void DeviceDoesntSuck(IMyDevice myDevice) {
Assert.False(myDevice.sucks());
}
}
}
namespace Test.MyApp.UWP {
public class TestMyDeviceUWP {
[Theory]
[ClassData new MyUWPBluetoothDevice()]
[ClassData new MyUWPSerialDevice()]
void DeviceDoesntSuck(IMyDevice myDevice) {
Test.MyApp.TestMyDevice.DeviceDoesntSuck(myDevice);
}
}
}
namespace Test.MyApp.Droid{
public class TestMyDeviceDroid {
[Fact]
void DeviceDoesntSuck() {
Test.MyApp.TestMyDevice.DeviceDoesntSuck(new MyDeviceDroid());
}
}
}
this is more maintainable since I only have one implementation of each test, but it is still a lot of duplication since I have to wrap each one on each platform
In summary, if anyone knows how to: run a whole battery of tests against different runtime-dependant implementations of an interface that live in different projects/namespaces, I'd be very interested to hear what you have to say.