Moq中带ref参数方法的Callback
创始人
2024-07-26 15:11:15
0

随着.NET世界中mock技术的普及,Moq也流行了起来,其部分原因是,它是专为那些刚接触mock技术或需要编写自定义mock对象的开发人员量身定做的类库。Moq舍弃了经典的Record/Reply范式,取而代之的是让测试者使用Lambda表达式设定行为的预期结果,并使用Castle DynamicProxy来截断mock对象的调用。

最近在使用的时候,当mock对象的方法的参数带ref关键字时感觉压力很大。

首先来重现一下案发现场,首先定义我们需要mock的接口:

  1. public interface ITestInterface  
  2. {  
  3. string TestMethodWithRef(ref string refStr, string str);  

接下来我们mock我们定义的接口的方法TestMethodWithRef,并指定方法被调用之后执行委托操作:

  1. [TestMethod]  
  2. public void Ref_Param_Test()  
  3. {  
  4. var mock = new Mock();  
  5. string refStr = "1";  
  6. string str = "2";  
  7. mock.Setup((m) => m.TestMethodWithRef(ref refStr, str)).Callback((string rs, string s) => Console.WriteLine(rs + s));  
  8. mock.Object.TestMethodWithRef(ref refStr, str);  
  9. mock.VerifyAll();  

上面的测试方法,看上去是没什么问题,编译也没什么问题,但运行测试的话悲剧发生了,抛出异常

System.ArgumentException: Invalid callback. Setup on method with parameters (String&,String) cannot invoke callback with parameters (String,String) 

这异常就是说Callback委托执行的方法的参数与Setup方法的参数对应不起来,有人也许马上就想说这样改改不就行了:

  1. mock.Setup((m) => m.TestMethodWithRef(ref refStr, str))  
  2. .Callback((ref string rs, string s) => Console.WriteLine(rs + s)); 

可惜微软老大很直接的告诉你lamada表达式里面的参数不能用ref和out:

Variables introduced within a lambda expression are not visible in the outer method 

这下子压力真就大了,淡定,淡定,相信google!找了下还真不少信息,可惜感觉有用的就两种解决方案。***种很直接,别用Moq伪造对象了,直接自己敲代码伪造接口或者对象以及相关方法,但感觉这解决方案有点坑爹。第二种就是委托执行的操作里面别传参数进去了:

  1. mock.Setup((m) => m.TestMethodWithRef(ref refStr, str)).Callback(() => Console.WriteLine(refStr + str)).Returns("").Verifiable(); 

怎么说第二种方案也还算比较满意,至少能解决大部分问题了。

差不多这事也算完了,可惜很不小心又踩了一个坑,我们修改下我们单元测试方法:

  1. [TestMethod]  
  2. public void Ref_Param_Test()  
  3. {  
  4. var mock = new Mock();  
  5. string refStr = "1";  
  6. string str = "1";  
  7. mock.Setup((m) => m.TestMethodWithRef(ref refStr, str)).Callback(() => { refStr = "2"; str = "2"; }).Returns("").Verifiable();  
  8. mock.Object.TestMethodWithRef(ref refStr, str);  
  9. mock.VerifyAll();  
  10. Assert.AreEqual("2", str);  
  11. Assert.AreEqual("2", refStr);  

直接看看这测试的逻辑,我想大部分人应该都会觉得没啥问题吧?

还是不放心,运行下吧,悲剧继续发生了,测试失败:Assert.AreEqual 失败。应为: <2>,实际为: <1>  

变量refStr的值还是“1”,这下子还真有趣了!

【编辑推荐】

  1. c#中的数据库访问工厂
  2. C#选择正确的集合进行编码
  3. .NET中值得体验的精妙设计
  4. ASP.NET控件10个最有用的属性详解

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
各种千兆交换机的数据接口类型详... 千兆交换机有很多值得学习的地方,这里我们主要介绍各种千兆交换机的数据接口类型,作为局域网的主要连接设...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
规避非法攻击 用好路由器远程管... 单位在市区不同位置设立了科技服务点,每一个服务点的员工都通过宽带路由器进行共享上网,和单位网络保持联...
范例解读VB.NET获取环境变... VB.NET编程语言的使用范围非常广泛,可以帮助开发人员处理各种程序中的需求,而且还能对移动设备进行...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...