5

我正在为我的 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 项目,其中包含单元测试。该项目可在此处获得

4

4 回答 4

2

您需要将Xamarin.Essentials NuGet 包添加到您的单元测试项目。

我强烈建议使用 Dependency Injection + Xamarin.Essentials.Interfaces,因为某些 Xamarin.Essentials API 未在 .NET Core 上实现,您需要创建自己的实现。

例如,以下是我在 .NET Core 中实现的一些 Xamarin.Essentials API,用于对我的GitTrends应用程序进行单元测试:

于 2020-11-13T17:27:05.307 回答
1

虽然您已经声明此时不能使主题函数异步,但是可以使测试异步。

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")
    }
}
于 2020-10-19T12:19:51.207 回答
1

这个问题可能与回调试图做什么有关。例如,如果您从单元测试中调用 Xamarin.Essentials 的 Connectivity 函数,它将不起作用(并且会抛出该类型的异常),因为它没有在移动平台上运行,因此没有实现该功能。

一个解决方案,至少我为这种类型的功能做了一个,是创建一个接口。因此,要继续上面关于连接功能的示例,我们可以这样做:

  1. 做一个界面

    public interface IConnectivityService {
    
       bool CanConnect()
    }
    
  2. 定义将在应用程序运行期间使用的实际实现,以及用于测试目的的实现

    public ConnectivityService : IConnectivityService {
    
       //implement the method
    
    }
    
    public ConnectivtyServiceMock : IConnectivityService {
    
       //implement the method, but this is a mock, so it can be very skinny
    
    }
    
  3. 更新您的视图/虚拟机以接受此接口,并在测试用例内部实例化它的模拟版本并将其传入。

在这种情况下,我们必须从单元测试中引用特定于设备的实现,我们必须将其抽象到接口中并使用该实现来代替

于 2020-11-18T20:27:35.490 回答
1

我检查了您的代码,它没有引发任何 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);
        }
于 2020-12-07T19:49:06.470 回答