使用 NUnit Test Runner 测试命令和导航的简单 Specflow

我们为什么需要这个?

目前在 Xamarin.Forms 中进行单元测试的方法是通过平台运行,因此你的测试必须在 ios,android,windows 或 mac UI 环境中运行在 IDE 中运行测试

Xamarin 还使用 Xamarin.TestCloud 产品提供了令人敬畏的 UI 测试,但是当想要实现 BDD 开发实践,并且能够测试 ViewModel 和 Commands,同时在本地或构建服务器上的单元测试运行器上廉价运行时,没有建成的方式。

我开发了一个库,允许使用 Specflow 和 Xamarin.Forms 轻松实现从 Scenarios 定义到 ViewModel 的功能,独立于用于 App 的任何 MVVM 框架(例如 XLabsMVVMCrossPrism

如果你是 BDD 的新手 ,请检查 Specflow out。

用法:

  • 如果你还没有,请从此处(或从你的 visual studio IDE)安装 specflow visual studio 扩展: https ://visualstudiogallery.msdn.microsoft.com/c74211e7-cb6e-4dfa-855d-df0ad4a37dd6

  • 将类库添加到 Xamarin.Forms 项目中。那是你的测试项目。

  • nuget 中的 SpecFlow.Xamarin.Forms 包添加到你的测试项目中。

  • 向你继承 TestApp 的测试项目添加一个类,并注册你的 views / viewmodels 对以及添加任何 DI 注册,如下所示:

    public class DemoAppTest : TestApp
    {
        protected override void SetViewModelMapping()
        {
            TestViewFactory.EnableCache = false;

            // register your views / viewmodels below
            RegisterView<MainPage, MainViewModel>();
        }

        protected override void InitialiseContainer()
        {
            // add any di registration here
            // Resolver.Instance.Register<TInterface, TType>();
            base.InitialiseContainer();
        }
    }
  • 将 SetupHook 类添加到测试项目中,以便为你添加 Specflow 挂钩。你将需要按照以下方式引导测试应用程序,提供你在上面创建的类以及你的应用程序初始视图模型:
    [Binding]
    public class SetupHooks : TestSetupHooks
    {   
        /// <summary>
        ///     The before scenario.
        /// </summary>
        [BeforeScenario]
        public void BeforeScenario()
        {
            // bootstrap test app with your test app and your starting viewmodel
            new TestAppBootstrap().RunApplication<DemoAppTest, MainViewModel>();
        }
    }
  • 你需要在你的 xamarin.forms 视图代码隐藏中添加一个 catch 块,以便忽略 xamarin.forms 框架,迫使你运行 app ui(我们不想做的事情):
        public YourView()
        {
            try
            {
                InitializeComponent();
            }
            catch (InvalidOperationException soe)
            {
                if (!soe.Message.Contains("MUST"))
                    throw;
            }
        }
  • 为项目添加 specflow 功能(使用 vs specflow 扩展附带的 vs specflow 模板)

  • 创建/生成继承 TestStepBase 的步骤类,将 scenarioContext 参数传递给基类。

  • 使用导航服务和帮助程序来导航,执行命令和测试视图模型:

  [Binding]
    public class GeneralSteps : TestStepBase
    {
        public GeneralSteps(ScenarioContext scenarioContext)
            : base(scenarioContext)
        {
            // you need to instantiate your steps by passing the scenarioContext to the base
        }

        [Given(@"I am on the main view")]
        public void GivenIAmOnTheMainView()
        {
            Resolver.Instance.Resolve<INavigationService>().PushAsync<MainViewModel>();           
            Resolver.Instance.Resolve<INavigationService>().CurrentViewModelType.ShouldEqualType<MainViewModel>();
        }
        
        [When(@"I click on the button")]
        public void WhenIClickOnTheButton()
        {
            GetCurrentViewModel<MainViewModel>().GetTextCommand.Execute(null);
        }

        [Then(@"I can see a Label with text ""(.*)""")]
        public void ThenICanSeeALabelWithText(string text)
        {           
            GetCurrentViewModel<MainViewModel>().Text.ShouldEqual(text);
        }
    }