如何在FakeItEasy中为泛型接口的out参数设置模拟值?
使用FakeItEasy模拟带out参数的泛型接口方法
问题场景
需要在xUnit测试中用FakeItEasy模拟泛型接口IFakeTest<T>的GetData方法(包含out参数),原代码及遇到的错误如下:
原测试代码
#region FakeItEasyDebugging public interface IFakeTest<T> : IDisposable where T : new() { bool GetData(string key, out T data); } public class TestClass { public int Foo { get; set; } = 0; } public class FakeTest { [Fact] public void TestFakeItEasy() { const string testKey = "some"; IFakeTest<TestClass> testObj = A.Fake<IFakeTest<TestClass>>(); A.CallTo(() => testObj.GetData(testKey, out data)).Returns(true).AssignsOutAndRefParameters(new TestClass()); } } #endregion
遇到的错误
- 直接使用
out data:报错CS0103,提示data在当前上下文中不存在 - 尝试
out TestClass data:报错CS8198,lambda表达式中不能声明变量 - 尝试
out TestClass:报错CS0118,TestClass是类型,此处需要变量
正确实现方式
FakeItEasy处理out参数时,需要满足C#语法要求的同时指定模拟行为,以下两种写法都可行:
方式1:提前声明变量作为占位符
[Fact] public void TestFakeItEasy() { const string testKey = "some"; IFakeTest<TestClass> testObj = A.Fake<IFakeTest<TestClass>>(); // 提前声明out参数对应的变量,初始值不影响模拟逻辑 TestClass data; A.CallTo(() => testObj.GetData(testKey, out data)) .Returns(true) .AssignsOutAndRefParameters(new TestClass()); // 验证模拟效果 var result = testObj.GetData(testKey, out var outputData); Assert.True(result); Assert.NotNull(outputData); Assert.Equal(0, outputData.Foo); }
方式2:使用A<T>.Ignored简化占位符
如果不需要在配置阶段使用该变量,可直接用FakeItEasy提供的A<T>.Ignored作为out参数的占位符:
[Fact] public void TestFakeItEasy() { const string testKey = "some"; IFakeTest<TestClass> testObj = A.Fake<IFakeTest<TestClass>>(); A.CallTo(() => testObj.GetData(testKey, out A<TestClass>.Ignored)) .Returns(true) .AssignsOutAndRefParameters(new TestClass()); // 验证模拟效果 var result = testObj.GetData(testKey, out var outputData); Assert.True(result); Assert.NotNull(outputData); }
原理说明
AssignsOutAndRefParameters方法会在模拟方法被调用时,将指定的值赋值给out/ref参数;提前声明的变量或A<T>.Ignored仅用于满足C#语法编译要求,FakeItEasy实际会用传入的目标值覆盖out参数。
内容的提问来源于stack exchange,提问作者path
相关产品推荐
相关产品推荐

