我可以在Visual Studio单元测试(类库)项目中使用Xamarin.Forms.DependencyService吗?

时间:2014-09-25 22:17:55

标签: unit-testing dependency-injection xamarin xamarin.forms vs-unit-testing-framework

我正在使用Xamarin Forms构建移动应用程序,并通过Xamarin Forms Labs插件利用MVVM。我的解决方案设置如下:

  • iOS项目
  • UI可移植类库项目(仅限Views / Xaml)
  • 核心可移植类库项目(ViewsModels / Models /其他)
  • 测试类库项目

我已经成功添加了测试项目,同时引用了Xamarin Forms和Xamarin Forms Labs,并且可以运行实例化ViewModel的测试。但是,当我使用Xamarin Forms Dependency Service来实现跨平台功能时,我认为我可以在测试库中使用它来为这些特定于平台的调用注入虚拟实现。这样我就可以更全面地测试View Models和其他所有东西。

但是在以下代码中:

    [TestMethod()]
    public void TestingDependencyInjection()
    {
        string strInfo = Xamarin.Forms.DependencyService.Get<Interfaces.ITestingInterface>().GetInformation();
        Assert.IsFalse(string.IsNullOrEmpty(strInfo));
    }

从Xamarin.Forms.Core.dll抛出了一个InvalidOperationException,其中包含以下信息:“在使用它之前,必须调用Xamarin.Forms.Init();”

但在测试项目中,“Init”不是Forms的成员!

我想我可以在Xamarin Forms中使用其他注射服务,但我希望不要这样做。

其他人试图这样做吗?

1 个答案:

答案 0 :(得分:4)

您必须将实现IPlatformServices的类分配给Device.PlatformServices静态属性。现在,这很棘手,因为IPlatformServices接口和Device.PlatformServices都是内部的。但它是可行的。

将您的unittest程序集命名为&#34; Xamarin.Forms.Core.UnitTests&#34;因为内部对于名称相似的程序集是可见的(在少数其他名称中)。

实施虚假的PlatformServices,即:

public class PlatformServicesMock: IPlatformServices
{
    void IPlatformServices.BeginInvokeOnMainThread(Action action)
    {
        throw new NotImplementedException();
    }
    ITimer IPlatformServices.CreateTimer(Action<object> callback)
    {
        throw new NotImplementedException();
    }
    ITimer IPlatformServices.CreateTimer(Action<object> callback, object state, int dueTime, int period)
    {
        throw new NotImplementedException();
    }
    ITimer IPlatformServices.CreateTimer(Action<object> callback, object state, long dueTime, long period)
    {
        throw new NotImplementedException();
    }
    ITimer IPlatformServices.CreateTimer(Action<object> callback, object state, TimeSpan dueTime, TimeSpan period)
    {
        throw new NotImplementedException();
    }
    ITimer IPlatformServices.CreateTimer(Action<object> callback, object state, uint dueTime, uint period)
    {
        throw new NotImplementedException();
    }
    Assembly[] IPlatformServices.GetAssemblies()
    {
        return new Assembly[0];
    }
    Task<Stream> IPlatformServices.GetStreamAsync(Uri uri, CancellationToken cancellationToken)
    {
        throw new NotImplementedException();
    }
    IIsolatedStorageFile IPlatformServices.GetUserStoreForApplication()
    {
        throw new NotImplementedException();
    }
    void IPlatformServices.OpenUriAction(Uri uri)
    {
        throw new NotImplementedException();
    }
    void IPlatformServices.StartTimer(TimeSpan interval, Func<bool> callback)
    {
        throw new NotImplementedException();
    }

    bool IPlatformServices.IsInvokeRequired
    {
        get
        {
            throw new NotImplementedException();
        }
    }
}

请注意,我没有在GetAssembly块中返回任何程序集(分析了用于实现接口的类型的程序集)。随意返回您需要的一系列程序集。

将PlatformServicesMock的实例分配给Device.PlatformServices:

var platformServicesProperty = typeof(Device).GetProperty("PlatformServices", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
        platformServicesProperty.SetValue(null, new PlatformServicesMock());

这是一个肮脏的解决方案,但它应该可行。另请注意,Visual Studio可能会绘制很多指示错误的波浪线(内部不可见),但编译得很好。

HTH

相关问题