如何封装实例且将调用转发给被封装实例成员?FakeItEasy配置疑问
问题原因
该问题的核心是FakeItEasy的动态代理机制仅能拦截虚方法:
- FakeItEasy生成的包装假对象是
DeletePaymentCardHandler的子类实例,只有标记为virtual的类方法才能被子类重写,进而被FakeItEasy拦截并触发转发到原实例的逻辑。 - 你的代码中
Handle方法未添加virtual修饰符,调用wrapperHandler.Handle时无法被FakeItEasy拦截,不会转发到你通过Resolve得到的原handler实例,而是直接执行DeletePaymentCardHandler定义的Handle逻辑。 - 此时执行
Handle逻辑的上下文是FakeItEasy生成的代理实例,而非原handler实例。代理实例的repository字段未被注入赋值,是FakeItEasy生成的默认假对象,因此会调用到假的repository。
你提到的官方文档“未配置的调用默认转发到原实例”的规则,仅适用于可被拦截的虚方法/接口方法,非虚方法不受该规则约束。
解决方法
方案1(推荐):将Handle方法标记为virtual
修改DeletePaymentCardHandler的Handle方法,添加virtual修饰符:
public virtual async Task Handle(DeletePaymentCard msg, CancellationToken cancellationToken) { await this.EnsurePaymentCardCanBeDeleted(msg, cancellationToken); var instance = await this.repository.GetById<Domain.CustomerFundingSources>(msg.CustomerId, cancellationToken); instance.Process(msg); await this.repository.Save(instance); }
修改后FakeItEasy可以正常拦截Handle调用并转发到原实例执行,此时Handle逻辑中的this指向已完成依赖注入的原handler,repository调用会走你注入的实例。
方案2:手动为代理实例赋值依赖
如果不能修改原有类的方法修饰符,可以在创建代理后手动同步原实例的依赖到代理实例:
var handler = this.Resolve<DeletePaymentCardHandler>(); var wrapperHandler = A.Fake<DeletePaymentCardHandler>(o => o.Wrapping(handler)); // 手动同步依赖 wrapperHandler.repository = handler.repository; A.CallTo(() => wrapperHandler.EnsurePaymentCardCanBeDeleted(A<DeletePaymentCard>._, A<CancellationToken>._ )) .Returns(Task.CompletedTask); await wrapperHandler.Handle(command, CancellationToken.None);
该方案不需要修改原有业务代码,但需要手动同步所有用到的依赖字段,容易出现漏配问题。
内容的提问来源于stack exchange,提问作者epitka
相关产品推荐
相关产品推荐

