【问题标题】:Need help testing Binding in Windows Phone 8需要帮助测试 Windows Phone 8 中的绑定
【发布时间】:2014-01-24 12:48:20
【问题描述】:

我希望有人已经面临并解决了这个问题,并且可以为我指出正确的方向。

所以我的其余单元测试工作正常:Core.Tests 对 ViewModels 进行了测试,以查看它们是否正常工作。现在我想为 Phone.Tests 设置一个测试项目,它只会测试绑定。所以假设在登录页面上,用户名文本框中输入了一些内容,并且该值应该在 ViewModel 中更新,反之亦然。

作为一个测试框架,我使用的是 WP Toolkit 测试框架,而不是 MS 框架; WP Toolkit 框架在手机本身上运行,这意味着它可以访问 UI 线程。

理论上,测试应该如下所示:

    [TestMethod]
    [Asynchronous]
    public void Username_Update_View_Should_Update_Model()
    {
        const string testUsername = "Testing";

        var usernameTextBox = GetUiElement<PhoneTextBox>("UsernamePhoneTextBox");

        // initial value
        Assert.AreEqual(null, _viewModel.Authorization.Username, "Default value should be blank");

        //
        usernameTextBox.Text = testUsername;

        //
        Assert.AreEqual(testUsername, _viewModel.Authorization.Username, "Binding not set for {0}", "Username");
    }

    private T GetUiElement<T>(string name) where T : UIElement
    {
        return (T)_view.FindName(name);
    }

现在,我需要以某种方式在 [TestInitialize] 方法中创建视图,这就是我认为我设置错误的地方。

我尝试过手动创建 ViewModel;然后我手动创建了 View,并将 DataContext 和 ViewModel(为了安全起见)绑定到创建的 viewModel。

此时,我希望更改任何一个属性上的一个属性应该会更新另一个属性。

当然错误是我的测试失败了。我不知道我是否应该查看自定义演示者(所有示例似乎都是针对 ios、droid。)我还尝试了以下方法:

    public class TestAppStart : MvxNavigatingObject, IMvxAppStart
    {
        public void Start(object hint = null)
        {
            ShowViewModel<UserLoginViewModel>();
        }
    }

然后在我的 testInitialize 上,我认为我可以启动它,但我想我需要找到 RegisterAppStart,一旦完成,尝试从 RootFrame 取回视图。

一定有更简单的方法……有人吗??

提前致谢。

已编辑:我将以下内容作为基础测试

    public abstract class BaseTest
{
    private IMvxIoCProvider _ioc;

    protected IMvxIoCProvider Ioc
    {
        get
        {
            return _ioc;
        }
    }

    public void Setup()
    {
        ClearAll();
    }

    protected virtual void ClearAll()
    {
        MvxSingleton.ClearAllSingletons();
        _ioc = MvxSimpleIoCContainer.Initialize();
        _ioc.RegisterSingleton(_ioc);
        _ioc.RegisterSingleton((IMvxTrace)new DebugTrace());
        InitialiseSingletonCache();
        InitialiseMvxSettings();
        MvxTrace.Initialize();
        AdditionalSetup();
    }

    private static void InitialiseSingletonCache()
    {
        MvxSingletonCache.Initialize();
    }

    protected virtual void InitialiseMvxSettings()
    {
        _ioc.RegisterSingleton((IMvxSettings)new MvxSettings());
    }

    protected virtual void AdditionalSetup()
    {
        _ioc.RegisterSingleton(Mock.Of<ISettings>);
        _ioc.RegisterSingleton<IApplicationData>(() => new ApplicationData());
        _ioc.RegisterSingleton<IPlatformSpecific>(() => new PlatformSpecific());
        _ioc.RegisterSingleton<IValidatorFactory>(() => new ValidatorFactory());

        //
        _ioc.RegisterType<IMvxMessenger, MvxMessengerHub>();
    }
}

在我的 TestClass 初始化时,我调用 base.Setup(),它会执行除 ViewDispatcher 之外的设置。不幸的是,我不知道如何使用该调度程序:

我想我真正要问的问题是:如何通过 MvvmCross 获得视图。

PS:实际上我很惊讶大多数人都不测试绑定;这不是最容易发生错误的地方吗?我很确定即使我的绑定不好,该项目也会编译 :) 可怕的那种让我想起早期的 asp 日子。

PS:我实际上有另一个测试 ViewModel 的 testProject;在那个 testProject 上,我设法按照以下指南进行连接

http://blog.fire-development.com/2013/06/29/mvvmcross-unit-testing-with-autofixture/

效果很好;并且还使用 autoFixture、NSubstitute 和 xUnit:我不能在 Phone Test 项目中使用它们中的任何一个。

【问题讨论】:

    标签: unit-testing mvvm windows-phone mvvmcross


    【解决方案1】:

    根据我的经验,测试绑定本身是非常不寻常的 - 大多数开发人员在 ViewModel 和 ValueConverter 级别停止测试。

    但是,如果您想测试绑定,那么这应该是可能的。我怀疑您当前测试中的唯一问题是您尚未初始化任何 MvvmCross 基础架构,因此 MvxViewModel 无法传播 INotifyPropertyChanged 事件。

    如果你想初始化这部分 MvvmCross 基础设施,那么一定要至少初始化:

    • MvvmCross IoC 容器
    • MvvmCross 主线程调度器

    这类似于 N=29 视频中的单元测试中所做的 - 请参阅 https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/blob/master/N-29-TipCalcTest/TipCalcTest.Tests/FirstViewModelTests.cs#L57

    对于您的应用,您可以使用以下方式执行此操作:

    public static class MiniSetup
    {
        public static readonly MiniSetup Instance = new MiniSetup();
    
        private MiniSetup()
        {            
        }
    
        public void EnsureInitialized(Context applicationContext)
        {
            if (MvxSimpleIoCContainer.Instance != null)
                return;
    
            var ioc = MvxSimpleIoCContainer.Initialize();
    
            ioc.RegisterSingleton<IMvxTrace>(new MvxDebugOnlyTrace());
            MvxTrace.Initialize();
    
            var mockDispatcher = new SimpleDispatcher();
            Ioc.RegisterSingleton<IMvxMainThreadDispatcher>(simpleDispatcher);
        }
    }
    

    SimpleDispatcher 类似于:

    public class SimpleDispatcher
        : MvxMainThreadDispatcher 
    {
        public readonly List<MvxViewModelRequest> Requests = new List<MvxViewModelRequest>();
    
        public bool RequestMainThreadAction(Action action)
        {
            action();
            return true;
        }
    }
    

    如果您希望获得更多 MvvmCross 功能(例如ShowViewModel 导航),那么您需要提供更多服务 - 例如。 IMvxViewDispatcher 之类的东西 - 随着这些数量的增加,你最好只运行一个完整的 MvxSetup 进程(就像你的主应用程序的 Setup 一样)

    【讨论】:

    • 嗨斯图尔特,感谢您的回复;现在回到代码。实际上,我在抽象 BaseTest 中有以下内容。哦,我不能在这里添加任何代码并返回;更新我原来的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-19
    • 1970-01-01
    • 1970-01-01
    • 2014-01-15
    • 2013-12-30
    • 2010-12-05
    • 2011-08-12
    相关资源
    最近更新 更多