I'm using Xamarin Studio to embark upon TDD using MvvmCross. 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.
But before I dive in further I want to code using TDD. How do I artificially setup the viewmodel and artificially publish the messages to it in my test harness? :
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
Any great tutorials on TDD with MvvmCross would be fantastic
Greg Shackles's talk at Evolve is a very good starting place for this - 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
A tutorial on MvvmCross Unit Testing - including Mocking - is available in N=29 on http://mvvmcross.wordpress.com/
A blog post is also available on 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? :
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:
_mockMvxMessenger = Fixture.Freeze<Mock<IMvxMessenger>> ();
_myViewModel = _fixture.Build<MyViewModel ().OmitAutoProperties().Create ();
The above assumes you inject an IMvxMessenger into your 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:
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));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With