简体   繁体   English

如何使用IMvxMessenger对MvvmCross进行单元测试

[英]How to unit test MvvmCross with IMvxMessenger

I'm using Xamarin Studio to embark upon TDD using MvvmCross. 我正在使用Xamarin Studio使用MvvmCross开始TDD。 I'm trying to first start by testing the effect of messages being published to the view model so that logic is performed only when the appropriate message is recieved. 我首先尝试测试发布的消息对视图模型的影响,以便仅在收到相应的消息时才执行逻辑。

I've hacked together some of Stuart's excellent tutorials resulting in successful propogation of location data to view models which then update some text controls, map markers, etc on the IOS views. 我已经将Stuart的一些优秀教程混合在一起,导致成功传播位置数据,以查看模型,然后在IOS视图上更新一些文本控件,地图标记等。

But before I dive in further I want to code using TDD. 但在我进一步深入研究之前,我想使用TDD进行编码。 How do I artificially setup the viewmodel and artificially publish the messages to it in my test harness? 如何人工设置viewmodel并在我的测试工具中人为地将消息发布到它? :

public class MyViewModel : MvxViewModel
{
    private readonly MvxSubscriptionToken _token;

    public MyViewModel(ILocationService service, IMvxMessenger messenger)
    {
        //weak reference
        _token = messenger.Subscribe<LocationMessage>(OnLocationMessage);
    }

    private void OnLocationMessage(LocationMessage locationMessage)
    {
        Lat = locationMessage.Lat;
        Lng = locationMessage.Lng;
        // Console.WriteLine("on loc msg {0:0.0000}, {1:0.0000}", Lat, Lng);
    }

    private double _lng;
    public double Lng
    {
        get { return _lng; }
        set
        {
            _lng = value;
            RaisePropertyChanged(() => Lng);
        }
    }

    private double _lat;
    public double Lat
    {
        get { return _lat; }
        set
        {
            _lat = value;
            RaisePropertyChanged(() => Lat);
        }
    }
}


[TestFixture()]
public class LocTest
{
    [Test()]
    public void LocationMessageIsRecieved()
    {
        // im using nsubstitute to mock with
        var locService = Substitute.For<ILocationService>();  
        var msgr = Substitute.For<IMvxMessenger>();
        var vm = new Map2ViewModel(locService, msgr);

        var locMsg = new LocationMessage(this, 1F, 2F);
        msgr.Publish(locMsg);

        var lat = vm.Lat;
        Assert.AreEqual(2F, lat);  // says lat is 0.0  and nunit doesnt let me debug the tests :(
    }
}

Any great tutorials on TDD with MvvmCross would be fantastic 有关MvvmCross的TDD的任何精彩教程都会很棒

Any great tutorials on TDD with MvvmCross would be fantastic 有关MvvmCross的TDD的任何精彩教程都会很棒

Greg Shackles's talk at Evolve is a very good starting place for this - http://xamarin.com/evolve/2013#session-7wb0etd3r8 Greg Shackles在Evolve的演讲是一个很好的起点 - http://xamarin.com/evolve/2013#session-7wb0etd3r8

His CodeCamp example contains a superb set of unit test examples - http://www.gregshackles.com/2013/09/nyc-code-camp-8-mobile-apps/ leading to https://github.com/gshackles/NycCodeCamp8/tree/master/CodeCamp.Core/tests/CodeCamp.Core.Tests/ViewModelTests 他的CodeCamp示例包含一组极好的单元测试示例 - http://www.gregshackles.com/2013/09/nyc-code-camp-8-mobile-apps/导致https://github.com/gshackles/ NycCodeCamp8 /树/主/ CodeCamp.Core /测试/ CodeCamp.Core.Tests / ViewModelTests

A tutorial on MvvmCross Unit Testing - including Mocking - is available in N=29 on http://mvvmcross.wordpress.com/ 关于MvvmCross单元测试的教程 - 包括模拟 - 可在N = 29的http://mvvmcross.wordpress.com/上获得。

A blog post is also available on http://blog.fire-development.com/2013/06/29/mvvmcross-enable-unit-testing/ 博客文章也可在http://blog.fire-development.com/2013/06/29/mvvmcross-enable-unit-testing/上找到。

How do I artificially setup the viewmodel and artificially publish the messages to it in my test harness? 如何人工设置viewmodel并在我的测试工具中人为地将消息发布到它? :

After setting up as described in the last link that Stuart posted, the pattern I have used to test MvxMessenger is to use Moq (along with AutoFixture ) to create a mock IMvxMessenger and inject it: 按照Stuart发布的最后一个链接所述进行设置之后,我用来测试MvxMessenger的模式是使用Moq (以及AutoFixture )创建一个模拟IMvxMessenger并将其注入:

_mockMvxMessenger = Fixture.Freeze<Mock<IMvxMessenger>> ();
_myViewModel = _fixture.Build<MyViewModel ().OmitAutoProperties().Create ();

The above assumes you inject an IMvxMessenger into your ViewModel. 以上假设您将一个IMvxMessenger注入ViewModel。

If you need to check that a message has been published, you can assert (verify) on the mock 如果您需要检查消息是否已发布,则可以在模拟上断言(验证)

_myViewModel.MyCommand.Execute (null);
_mockMvxMessenger.Verify (m => m.Publish (It.IsAny<MyMvxMessage>()), Times.Once);

If you need to trigger a message, then grab the subscription Action and fire it when you like 如果您需要触发消息,则获取订阅操作并在您喜欢时触发它

Do this after freezing the Mock but before building the ViewModel: 在冻结Mock之后但在构建ViewModel之前执行此操作:

private Action<MyMvxMessage> _callbackAction; // class scope var
_mockMvxMessenger.Setup (n => n.Subscribe<MyMvxMessage> (It.IsAny<Action<MyMvxMessage>> (), It.IsAny<MvxReference>(), It.IsAny<string>())).Callback<Action<MyMvxMessage>, MvxReference, string> ((action,mvxref,tag) => _callbackAction = action);

Then in your test you can 'fire the message' by just calling 然后在您的测试中,您可以通过调用来“触发消息”

_callbackAction(new MyMvxMessage(this));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM