Caliburn.Micro WindowManager测试:Mock ViewModel注入失效问题
解决Mock WindowManager时ViewModel属性丢失的问题
你的问题核心在于C#的参数传递机制:你在Mock的Callback里尝试把vm替换成mockVM,但这只是修改了参数的副本,根本影响不到原方法里创建的那个TestViewModel实例。咱们一步步来解决:
为什么原来的测试无效?
原方法ShowDialog里是自己new了一个TestViewModel,然后把这个实例的引用传给_windowManager.ShowDialog。在你的Mock回调里,vm是这个引用的副本——你把副本指向mockVM,原方法里的vm变量还是牢牢指向原来的实例,所以后续DialogResultTest = vm.CoolText拿的还是原实例的空值。
解决方案1:重构原方法,支持ViewModel注入(推荐)
这是最符合可测试性原则的做法,让ShowDialog支持传入ViewModel(用可选参数保持原有调用的兼容性):
// 重构后的ShowDialog方法 public void ShowDialog(TestViewModel vm = null) { // 如果没传入vm,就创建新的,保持原有逻辑 vm = vm ?? new TestViewModel(); _windowManager.ShowDialog(vm); DialogResultTest = vm.CoolText; }
然后测试代码就可以直接传入你预先准备好的mockVM,不需要在Callback里折腾:
[Test] public void TestShowDialog() { // 准备测试用的ViewModel TestViewModel mockVM = new TestViewModel(); mockVM.CoolText = "test"; // Mock WindowManager Mock<IWindowManager> wmMock = new Mock<IWindowManager>(); wmMock.Setup(w => w.ShowDialog(mockVM, It.IsAny<object>(), It.IsAny<IDictionary<string, object>>())) .Returns(true); // 实例化主ViewModel并测试 MainViewModel mainVM = new MainViewModel(wmMock.Object); mainVM.ShowDialog(mockVM); Assert.That(mainVM.DialogResultText, Is.EqualTo("test")); }
解决方案2:不重构原方法,修改传入实例的属性(临时方案)
如果因为项目限制不能修改原方法,那可以在Mock的Callback里直接修改传入的原ViewModel实例的属性,而不是替换整个对象:
[Test] public void TestShowDialog() { Mock<IWindowManager> wmMock = new Mock<IWindowManager>(); // 在Callback里修改传入的ViewModel的CoolText属性 wmMock.Setup(w => w.ShowDialog(It.IsAny<object>(), It.IsAny<object>(), It.IsAny<IDictionary<string, object>>())) .Returns(true) .Callback<object, object, IDictionary<string, object>>((vm, obj, dic) => { // 把传入的object转成TestViewModel,然后设置属性 if (vm is TestViewModel targetVm) { targetVm.CoolText = "test"; } }); MainViewModel mainVM = new MainViewModel(wmMock.Object); mainVM.ShowDialog(); Assert.That(mainVM.DialogResultText, Is.EqualTo("test")); }
这样,原方法里创建的TestViewModel在调用ShowDialog后,其CoolText会被回调修改,后续DialogResultTest就能拿到正确的值了。
内容的提问来源于stack exchange,提问作者Tim Kathete Stadler
相关产品推荐
相关产品推荐

