How do I write a NUnit test for MvvmCross MvxCommand when my command needs CommandParameter of type integer.
testListViewModel.EditCommand.Execute(null);
This one is not an option since i have this ViewModel. CanExecute proceeds if parameter is passed.
public class TestListViewModel : MvxViewModel
{
private readonly ITestService _testService;
private readonly IDialogService _dialogService;
public TestListViewModel(ITestService testService, IDialogService dialogService)
{
_testService = testService;
_dialogService = dialogService;
}
public MvxCommand<int> EditCommand { get { return new MvxCommand<int>(Edit, id => id > 0); } }
private void Edit(int asTestID) { ShowViewModel<TestViewModel>(new { asTestID }); }
}
I use NUnit + Moq + Cirrious.MvvmCross.Test.Core references in my test project and have this structure.
public class MockDispatcher : MvxMainThreadDispatcher, IMvxViewDispatcher
{
public readonly List<MvxViewModelRequest> Requests = new List<MvxViewModelRequest>();
public readonly List<MvxPresentationHint> Hints = new List<MvxPresentationHint>();
public bool RequestMainThreadAction(Action action)
{
action();
return true;
}
public bool ShowViewModel(MvxViewModelRequest request)
{
Requests.Add(request);
return true;
}
public bool ChangePresentation(MvxPresentationHint hint)
{
Hints.Add(hint);
return true;
}
}
[TestFixture]
class TestListViewModelTest : MvxIoCSupportingTest
{
[Test]
public void TestListViewModel_OnEdit_ShowTestViewModel()
{
//Arrange
base.ClearAll();
var mockDispatcher = new MockDispatcher();
Ioc.RegisterSingleton<IMvxViewDispatcher>(mockDispatcher);
Ioc.RegisterSingleton<IMvxMainThreadDispatcher>(mockDispatcher);
var mockDialogService = new Mock<IDialogService>();
var mockTestService = new Mock<ITestService>();
var testListViewModel = new TestListViewModel(mockTestService.Object, mockDialogService.Object);
//Act
testListViewModel.EditCommand.Execute(2); //this line is failing
//Assert
Assert.AreEqual(1, mockDispatcher.Requests.Count);
var request = mockDispatcher.Requests[0];
Assert.AreEqual(typeof(TestViewModel), request.ViewModelType);
Assert.AreEqual((2).ToString(), request.ParameterValues["asTestID"]);
}
}
When i run the test it throws MvxIoCResolveException with this call stack. I tried to debug it and my code literally fails on MvxNavigatingObject.ShowViewModel() where the parameter is an object and tries to call parameterValuesObject.ToSimplePropertyDictionary().
In the static function ToSimplePropertyDictionary(this object input) propertyInfos enumerator is null, so it cant call foreach (var propertyInfo in propertyInfos).
The call stack that I get from running the test is:
Cirrious.CrossCore.Exceptions.MvxIoCResolveException : Failed to resolve type Cirrious.MvvmCross.Platform.IMvxStringToTypeParser
at Cirrious.CrossCore.IoC.MvxSimpleIoCContainer.Resolve(Type t)
at Cirrious.CrossCore.IoC.MvxSimpleIoCContainer.Resolve()
at Cirrious.MvvmCross.MvxSingletonCache.get_Parser()
at Cirrious.MvvmCross.Platform.MvxSimplePropertyDictionaryExtensionMethods.<ToSimplePropertyDictionary>b__7(PropertyInfo property)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at Cirrious.MvvmCross.Platform.MvxSimplePropertyDictionaryExtensionMethods.ToSimplePropertyDictionary(Object input)
at Cirrious.MvvmCross.ViewModels.MvxNavigatingObject.ShowViewModel(Object parameterValuesObject, IMvxBundle presentationBundle, MvxRequestedBy requestedBy)
at App.Core.ViewModels.TestListViewModel.Edit(Int32 asTestID) in TestListViewModel.cs: line 37
at App.Tests.Test.TestListViewModelTest.TestListViewModel_OnEdit_ShowTestViewModel() in TestListViewModelTest.cs: line 97
Any help would be appreciated!
When you call ShowViewModel with a parameter, there are a few different ways to do this. This determines how MvvmCross calls your Init method.
You are calling ShowViewModel with an anonymous type, but without property names. These property names must match the parameter names in your Init method.
So instead of this:
Do this:
Or this:
See https://github.com/MvvmCross/MvvmCross/wiki/View-Model-Lifecycle#2-init