使用接口Mock对象属性时无法传入被测方法的问题
解决Mock非虚属性的单元测试问题
问题根源
你用Mock<MyProduct>().As<IBaseProduct>()配置的Mock,本质是让Mock对象同时实现IBaseProduct接口,但MyProduct自身继承自BaseProduct的Name属性并没有被Mock。当你把Mock对象当作IBaseProduct时,读取的是接口Mock的属性值;但强制转换为MyProduct后,调用的是原类未被赋值的Name属性,所以返回null。
可行解决方案(无需修改原类)
方案1:反射设置非虚属性值 + Moq CallBase
直接创建MyProduct的Mock,通过反射给Name属性赋值,同时启用CallBase保证基类方法正常执行:
// 创建MyProduct的Mock实例,启用CallBase让未Mock的方法/属性调用原实现 var productMock = new Mock<MyProduct> { CallBase = true }; // 通过反射获取BaseProduct的Name属性并设置值 var nameProp = typeof(BaseProduct).GetProperty( "Name", BindingFlags.Public | BindingFlags.Instance ); nameProp.SetValue(productMock.Object, "Special Name"); // 执行测试逻辑 var testState = new State(); var result = Apply(productMock.Object, testState); // 验证结果 Assert.Equal(0, testState.MyProperty); Assert.Null(result);
方案2:动态拦截属性Getter(灵活切换测试值)
如果需要在测试中动态切换Name的值,可以结合Moq的拦截机制,直接指定Getter的返回值:
var expectedName = "Special Name"; var productMock = new Mock<MyProduct> { CallBase = true }; // 拦截Name属性的Getter,返回预设值 productMock.SetupGet(p => p.Name).Returns(expectedName); // 测试流程同方案1
说明
两种方案都不需要修改MyProduct和BaseProduct的代码,核心是绕过非虚属性无法直接Mock的限制,要么直接操作属性的实际值,要么拦截Getter返回预设值,确保Apply()方法中强制转换为MyProduct后能读取到正确的Name值。
内容的提问来源于stack exchange,提问作者Ava Stark
相关产品推荐
相关产品推荐

