如何用FakeItEasy验证公共方法调用?单元测试断言失败求解
问题:FakeItEasy单元测试断言失败,Play方法未触发Start调用
问题重现
单元测试中调用Fake生成的IPlayer实例的Play()方法后,断言Start(1)被调用失败,错误信息显示仅Play()被调用:
Message:
FakeItEasy.ExpectationException :Assertion failed for the following call:
AsyncConsole.example1.IPlayer.Start(i: 1)
Expected to find it once or more but didn't find it among the calls:
1: IPlayer.Play()
相关代码
接口与实现类
public interface IPlayer { public void Play(); public void Start(int i); } public class Player : IPlayer { public void Play() { Start(1); } public void Start(int i) { Console.WriteLine("Start " + i); } }
原测试类
using FakeItEasy; using Xunit; namespace TestProject { public class TestPlayer { [Fact] public void Play_WhenCalled_ShouldCallStart() { var player = A.Fake<IPlayer>(); player.Play(); //assert A.CallTo(() => player.Start(1)).MustHaveHappened(); } } }
原因分析
A.Fake<IPlayer>()生成的是完全模拟的Fake对象,FakeItEasy会为接口方法生成空实现。调用该Fake对象的Play()时,并不会执行Player类中Play()的真实逻辑(即调用Start(1)),仅会记录Play()的调用行为,因此断言Start(1)被调用必然失败。
解决方案
方案1:测试真实Player类的行为(推荐)
如果测试目标是验证Player类中Play()是否正确调用自身的Start(1),需创建Player的部分模拟(Partial Fake),让FakeItEasy执行Play()的真实逻辑,同时监控Start()的调用:
using FakeItEasy; using Xunit; using AsyncConsole.example1; // 引入Player所在命名空间 namespace TestProject { public class TestPlayer { [Fact] public void Play_WhenCalled_ShouldCallStart() { // 创建Player的Partial Fake,配置调用基类真实方法 var player = A.Fake<Player>(options => options.CallsBaseMethods()); player.Play(); // 断言Start(1)被调用至少一次 A.CallTo(() => player.Start(1)).MustHaveHappened(); } } }
方案2:配置Fake对象的Play()方法触发Start()
如果测试目标是验证依赖IPlayer的其他组件行为,而非Player自身实现,可手动配置Fake对象的Play()方法调用Start(1):
using FakeItEasy; using Xunit; namespace TestProject { public class TestPlayer { [Fact] public void Play_WhenCalled_ShouldCallStart() { var player = A.Fake<IPlayer>(); // 配置调用Play()时自动执行Start(1) A.CallTo(() => player.Play()).Invokes(() => player.Start(1)); player.Play(); A.CallTo(() => player.Start(1)).MustHaveHappened(); } } }
内容的提问来源于stack exchange,提问作者Mike Bluer
相关产品推荐
相关产品推荐

