Moq中带ref参数方法的Callback

开发 后端
Moq是.NET平台上流行的mock类库。mock对象的方法的参数带ref关键字时感觉压力很大。本文主要分析Moq在进行单元测试时遇到的问题。

随着.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<ITestInterface>();  
  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<ITestInterface>();  
  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个最有用的属性详解
责任编辑:于铁 来源: 博客园
相关推荐

2009-08-13 09:47:57

调用JSP EL表达式带参数方法

2021-10-04 14:56:09

机器学习函数参数

2010-10-08 16:55:44

MySql存储过程

2009-08-04 14:44:40

callback实现机ASP.NET2.0

2018-04-13 06:46:43

无服务器单元测试IT云

2022-09-27 11:01:08

Python装饰器

2009-09-17 13:26:55

.NET方法签名

2009-07-22 07:53:00

Scala无参数方法

2009-09-22 13:31:28

Hibernate C

2009-09-23 17:28:55

Hibernate C

2010-11-15 10:40:58

Oracle启动参数

2009-07-09 00:25:00

Scala参数化

2011-08-23 13:14:05

JDBC带输出参数的存储过程

2024-10-28 08:07:17

2017-02-17 10:07:02

AndroidMVP模式实例

2023-10-07 08:21:16

开源软件Moq

2020-05-19 20:45:27

MySQLref优化器

2009-07-14 15:53:21

光纤参数测试

2024-02-02 11:03:11

React数据Ref

2023-03-17 08:00:34

OpenCVCvType错误
点赞
收藏

51CTO技术栈公众号