问题描述
我正在为我的Xamarin.Forms应用程序运行单元测试,并且单元测试抛出Xamarin.Essentials.NotImplementedInReferenceAssemblyException
:
我已经使用NUnit 3.12.0为该应用程序创建了一个单元测试项目,并编写了以下代码来测试该功能。
[TestFixture()]
public class Test
{
[test()]
public void TestCase()
{
AutoResetEvent autoEvent = new AutoResetEvent(true);
SomeClass someClass = new SomeClass();
someClass.someFunction((response) =>
{
Assert.AreEqual(response,"Hello")
autoEvent.Set();
});
autoEvent.WaitOne(); //** Xamarin.Essentials.NotImplementedInReferenceAssemblyException thrown here**
}
}
以下是Xamarin.Forms应用中正在测试的代码:
public class SomeClass
{
public void SomeFunction(Action<string> callback)
{
// asynchronous code...
callback("Hello");
}
}
上述功能在Xamarin.Forms应用程序中正常运行。
注意:我读到可以使用await / async,但是,我将不得不在整个项目中进行更改。目前,这不是可行的解决方案。
修改1: 我创建了一个示例Xamarin.Forms项目,其中包含单元测试。该项目可用here
解决方法
虽然您已经声明此时无法使此主题函数异步,但是可以使测试异步。
TaskCompletionSource
可用于等待回调被调用。
[TestFixture()]
public class Test {
[Test()]
public async Task TestCase() {
//Arrange
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
Action<string> callback = (arg) => {
tcs.TrySetResult(arg);
};
SomeClass someClass = new SomeClass();
//Act
someClass.SomeFunction(callback);
string response = await tcs.Task;
//Assert
Assert.AreEqual(response,"Hello")
}
}
,
您需要将Xamarin.Essentials NuGet Package添加到单元测试项目中。
我强烈建议您使用Dependency Injection + Xamarin.Essentials.Interfaces,因为某些Xamarin.Essentials API不在.NET Core上实现,因此您需要创建自己的实现。
例如,以下是一些Xamarin.Essentials APIs I implemented in .NET Core用于对我的GitTrends应用进行单元测试:
- AppInfo
- Browser
- DeviceInfo
- FileSystem
- Launcher
- MainThread
- Preferences
- SecureStorage
- VersionTracking
该问题可能与回叫正试图执行的操作有关。例如,如果您从单元测试中调用Xamarin.Essentials的连接功能,则该功能将无法工作(并抛出该类型的异常),因为该功能未在移动平台上运行,因此未实现该功能。
对此的一种解决方案是创建一个接口,这至少是我为该类型的功能所做的。因此,继续上面关于连接功能的示例,我们可以这样做:
-
建立界面
public interface IConnectivityService { bool CanConnect() }
-
定义将在应用程序运行期间使用的实际实现以及用于测试的目的
public ConnectivityService : IConnectivityService { //implement the method } public ConnectivtyServiceMock : IConnectivityService { //implement the method,but this is a mock,so it can be very skinny }
-
更新您的View / VM以接受此接口,然后在测试用例中实例化该接口的模拟版本并将其传入。
在这种情况下,我们必须从单元测试中引用特定于设备的实现,我们必须在接口中将其抽象出来,而改用该实现
,我检查了您的代码,它没有引发任何Xamarin.Essentials异常。要运行单元测试,我必须添加“ NUnit3TestAdapter” nuget包。
您将必须等待回调,否则测试将崩溃。您可以使用@Nkosi建议的TaskCompletionSource。
[Test()]
public async Task TestCase()
{
XamarinMock.Init();
WebApi webApi = new WebApi();
TaskCompletionSource<HttpResponseMessage> tcs = new TaskCompletionSource<HttpResponseMessage>();
Action<HttpResponseMessage> callback = (arg) => {
tcs.TrySetResult(arg);
};
webApi.Execute(callback);
var response = await tcs.Task;
Console.WriteLine(response);
Assert.AreEqual(response.StatusCode,HttpStatusCode.OK);
}