如何Mock接口的特定实现类实例?以IIdentity与ClaimsIdentity为例
解决Mock IIdentity并替换Claims的问题
直接搞定你的当前问题
你的核心卡点在于:你Mock的是IIdentity接口,但控制器里把它强制转换成ClaimsIdentity——而Mock出来的IIdentity实例根本不是ClaimsIdentity的子类,强制转换必然失败,更别说访问Claims属性了。
这里有两种简单可行的解决方式:
方法1:直接Mock ClaimsIdentity类
ClaimsIdentity本身实现了IIdentity接口,而且它的Claims属性是虚属性,所以可以直接用NSubstitute Mock它:
var mockClaim = new Claim("test", "test"); // 直接Mock ClaimsIdentity,而非IIdentity var identity = Substitute.For<ClaimsIdentity>(); // 配置Claims属性的返回值 identity.Claims.Returns(new List<Claim> { mockClaim }); // 传入控制器,因为ClaimsIdentity是IIdentity的实现 var controller = new MyController(identity);
这样控制器里的_userIdentity = identity as ClaimsIdentity;会成功,因为identity本身就是ClaimsIdentity的Mock实例。
方法2:使用真实的ClaimsIdentity实例(更推荐)
测试场景下,如果ClaimsIdentity可以直接实例化,完全没必要Mock它,直接创建带指定Claim的真实实例更简单可靠:
var claims = new List<Claim> { new Claim("test", "test") }; // 创建真实的ClaimsIdentity,指定Claim和认证类型 var identity = new ClaimsIdentity(claims, "TestAuthentication"); var controller = new MyController(identity);
关于「在接口Mock中Mock特定类实现」的问题
很遗憾,这种技巧基本不可行。原因是:
- Mock框架(比如NSubstitute)生成的接口Mock实例,是动态创建的一个全新的类,这个类只实现了目标接口,和你想要的具体实现类(比如
ClaimsIdentity)没有任何继承关系。所以强制转换必然失败,更没法Mock该实现类的成员。
如果你的代码依赖接口,但内部又需要访问具体实现的成员,这其实是代码设计上的小瑕疵——接口的意义就是抽象掉具体实现的细节。不过如果不想重构现有代码,优先选择上面两种方法:要么Mock具体实现类(如果它的成员是可Mock的,比如虚属性/方法),要么直接使用真实实例。
内容的提问来源于stack exchange,提问作者user9530048
相关产品推荐
相关产品推荐

