当我的命令需要整数类型的CommandParameter时,如何为MvvmCross MvxCommand编写NUnit测试。
testListViewModel.EditCommand.Execute(null);
这个不是一个选项,因为我有这个ViewModel。如果传递参数,则执行CanExecute。
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 }); }
}
我在我的测试项目中使用NUnit + Moq + Cirrious.MvvmCross.Test.Core引用并具有此结构。
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"]);
}
}
当我运行测试时,它会使用此调用堆栈抛出MvxIoCResolveException。我尝试调试它,我的代码在MvxNavigatingObject.ShowViewModel()上失败,其中参数是一个对象并尝试调用 parameterValuesObject.ToSimplePropertyDictionary()。
在静态函数中 ToSimplePropertyDictionary(此对象输入) propertyInfos 枚举数为null,因此无法调用 foreach(propertyInfos中的var propertyInfo) 。
我从运行测试中获得的调用堆栈是:
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
任何帮助将不胜感激!
答案 0 :(得分:4)
// for navigation parsing
Ioc.RegisterSingleton<IMvxStringToTypeParser>(new MvxStringToTypeParser());
答案 1 :(得分:0)
使用参数调用 ShowViewModel 时,有几种不同的方法可以执行此操作。这决定了MvvmCross如何调用 Init 方法。
您使用匿名类型调用 ShowViewModel ,但没有属性名称。这些属性名称必须与 Init 方法中的参数名称匹配。
所以不要这样:
private void Edit(int asTestID) { ShowViewModel<TestViewModel>(new { asTestID }); }
这样做:
// simply-Typed parameters
private void Edit(int asTestID) { ShowViewModel<TestViewModel>(asTestID); }
或者这个:
// a single Typed parameter object with simply-Typed properties
private void Edit(int asTestID) { ShowViewModel<TestViewModel>(new { ID = asTestID }); }
请参阅https://github.com/MvvmCross/MvvmCross/wiki/View-Model-Lifecycle#2-init