You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用接口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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 10:43:14