基于VS2012 Fakes框架的TDD实战——私有成员,静态成员模拟.doc_第1页
基于VS2012 Fakes框架的TDD实战——私有成员,静态成员模拟.doc_第2页
基于VS2012 Fakes框架的TDD实战——私有成员,静态成员模拟.doc_第3页
基于VS2012 Fakes框架的TDD实战——私有成员,静态成员模拟.doc_第4页
基于VS2012 Fakes框架的TDD实战——私有成员,静态成员模拟.doc_第5页
已阅读5页,还剩3页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

、目录一、前言二、需求说明三、准备工作四、开工1. 编写测试用例与实现代码 2. 静态属性的模拟 3. 私有方法的测试 4. 私有方法的模拟 五、总结六、源码下载一、前言上文书(基于VS2012 Fakes框架的TDD实战接口模拟)把接口模拟的部分演示完了,接口模拟也是Mock框架最基本的功能了吧,比如很易用的Moq框架,就非常容易模拟出接口中定义的操作返回的结果。Moq也有局限性,比如不能模拟密封类,不能直接模拟静态方法等,而这些需求在微软VS2012带来的Fakes框架中都能得到很好的解决。二、需求说明一个项目的开发中,最见怪不怪的就是需求的变更了,比如我们这个用户名重复性检查的功能,它就变了,变化如下: 给未激活用户信息添加有效期属性,防止用户名被恶意占用 三、准备工作修改MemberInactive类如下: 1 public class MemberInactive : Entity 2 3 public string UserName get; set; 4 5 public string Password get; set; 6 7 public string Email get; set; 8 9 / 10 / 激活过期时间11 / 12 public DateTime Expiration get; set; 13 四、开工1. 编写测试用例与实现代码先编写一个检查未激活用户信息有效性的方法的测试用例,现在是2012年8月26日,所以定MemberInactive的过期时间为2012年8月27日。方便起见,我们先把IsMemberInactiveValid方法的可访问性定为public,用使可以用原来的方式来进行测试2. 1 TestMethod3. 2 public void IsMemberInactiveValid_有效的_过期时间大于当前时间()4. 3 5. 4 var memberInactive = new MemberInactive Expiration = new DateTime(2012, 8, 27) ;6. 5 Assert.IsTrue(_accountService.IsMemberInactiveValid(memberInactive);6 在类AccountService编写IsMemberInactiveValid方法让测试通过1 public bool IsMemberInactiveValid(MemberInactive memberInactive)2 3 var dtNow = DateTime.Now;4 return memberInactive.Expiration.CompareTo(dtNow) = 0;5 7. 静态属性的模拟测试通过了,但上面的测试用例有个问题,今天能跑通过,后天呢,到了28号,就注定是失败的了,因为实现方法中有一个外部依赖DateTime.Now,自动化测试中,方法体范围内的所有外部依赖都应该被模拟即你要测的仅是这个方法内的代码的正确性,不应该受外界影响。 现在我们来模拟DateTime.Now,这是一个静态的公共属性。在mscorlib.dll程序集System命名空间下实现的。所以需要创建System的Fakes程序集。静态成员的模拟将用到Shim类型的模拟类(Fakes框架生成的模拟类有两种,Stub和Shim,具体请参考官方文档)修改上面的测试用例如下: 1 TestMethod 2 public void IsMemberInactiveValid_有效的_过期时间大于当前时间() 3 4 var memberInactive = new MemberInactive Expiration = new DateTime(2012, 8, 27) ; 5 /Assert.IsTrue(_accountService.IsMemberInactiveValid(memberInactive); 6 using (ShimsContext.Create() 7 8 ShimDateTime.NowGet = () = new DateTime(2012, 8, 26); 9 Assert.IsTrue(_accountService.IsMemberInactiveValid(memberInactive);10 11 第8行即模拟了DateTime.Now的返回值,这时,即使你把系统时间修改为28号,这个测试也能通过,因为现在测试的运行已经与系统时间无关了。8. 私有方法的测试上面的例子为了承接上篇写测试用例的方法把IsMemberInactiveValid方法设成了public,但实际上这个方法应该是私有的,现在把方法的可访问性改为private,原来的测试用例当然是不能通过的,因为这个方法找不到了。把测试用例改为如下: TestMethod public void IsMemberInactiveValid_有效的_过期时间大于当前时间() var memberInactive = new MemberInactive Expiration = new DateTime(2012, 8, 27) ; using (ShimsContext.Create() ShimDateTime.NowGet = () = new DateTime(2012, 8, 26); var po = new PrivateObject(new AccountService(); var result = po.Invoke(IsMemberInactiveValid, new object memberInactive); Assert.IsTrue(bool) result); 测试通过,私有成员的访问用到了PrivateObject,其实这个类也没什么奇特的地方,只是封装了反射的相关操作,让我们调用更方便些9. 私有方法的模拟在把调用IsMemberInactiveValid的代码加入UserNameExistsCheck方法之前,千万别忘记了在测试类初始化的代码中把IsMemberInactiveValid模拟出来,否则加入之后原来的测试用例就有可能无法通过了。下面这个测试用例就通不过了1 TestMethod2 public void UserNameExistsCheck_用户存在_用户在用户数据库中不存在_and_注册需要激活_用户在未激活用户数据库中存在()3 4 var userName = 柳柳英侠;5 var configName = configName;6 _member = null;7 _configInfo.RegisterConfig.NeedActive = true;8 Assert.IsTrue(_accountService.UserNameExistsCheck(userName, configName);9 不过这个问题先放下,我们先来看看私有成员应该怎样来模拟,将用到AccountService类的模拟类,因为这个私有方法是这个类的成员,如下的测试用例: 1 TestMethod 2 public void UserNameExistsCheck_用户存在_用户在用户数据库中不存在_and_注册需要激活_and_用户在未激活用户数据库中存在_and_未激活用户信息有效() 3 4 var userName = 柳柳英侠; 5 var configName = configName; 6 _member = null; 7 _configInfo.RegisterConfig.NeedActive = true; 8 using (ShimsContext.Create() 9 10 ShimAccountService.AllInstances.IsMemberInactiveValidMemberInactive = (accountService, memberInactive) = true;11 Assert.IsTrue(_accountService.UserNameExistsCheck(userName, configName); 12 13 根据测试用例修改UserNameExistsCheck方法代码如下(第26行) 1 public bool UserNameExistsCheck(string userName, string configName) 2 3 if (string.IsNullOrEmpty(userName) 4 5 throw new ArgumentNullException(userName); 6 7 if (string.IsNullOrEmpty(configName) 8 9 throw new ArgumentNullException(configName);10 11 var member = MemberDao.GetByName(userName);12 if (member != null)13 14 return true;15 16 var configInfo = ConfigInfoDao.GetByName(configName);17 if (configInfo = null)18 19 throw new NullReferenceException(系统配置信息为空。);20 21 if (!configInfo.RegisterConfig.NeedActive)22 23 return false;24 25 var memberInactive = MemberInactiveDao.GetByName(userName);26 if (memberInactive != null & IsMemberInactiveValid(memberInactive)27 28 return true;29 30 return false;31 测试通过。现在来解决那个未通过的测试用例,按照TDD的原则,我们不能去修改测试用例来使它通过。不能通过的原因也就是IsMemberInactiveValid的模拟没有在测试类中进行初始化,下面我们来初始化它。由上面的测试用例可以看到,在私有成员的模拟中,测试方法的执行结果必须放在using语句中,而using语句实质也就是自动化了IDisposable接口,所以我们完全可以把它拆开,然后手动调用Dispose即可在测试类AccountServiceTest添加一个私有字段来存储ShimsContext.Create(),一个私有字段存储IsMemberInactiveValid的模拟结果:1 private IDisposable _shimsContext = ShimsContext.Create();2 private bool _isMemberInactiveValid = true;在标记TestInitialize的MyTestInitialize方法中添加IsMemberInactiveValid方法的模拟1 ShimAccountService.AllInstances.IsMemberInactiveValidMemberInactive = (accountService, memberInactive) = _isMemberInactiveValid;取消标记TestCleanup()的MyTestCleanup方法的注释,添加 ShimsContext.Create()的 Dispose调用1 / 在每个测试运行完之后,使用 TestCleanup 来运行代码2 TestCleanup()3 public void MyTestCleanup()4 5 _shimsContext.Dispose();6 这样,初始化完毕,再运行全部测试用例,全绿,心情大好(o)至此,我认为要讲的大概都讲到了,当然,Fakes框架还有很多功能,有待大家挖掘。五、总结总结说点什么呢,总结一下TDD吧开发过程:1. 快速新增一个测试 2. 运行所有的测试(有时候只需要运行一个或一部分),发现新增的测试不能通过 3. 做一些小小的改动,尽快地让测试程序可运行,为此可以在程序中使用一些不合情理的方法 4. 运行所有的测试,并且全部通过 5. 重构代码,以消除重复设计,优化设计结构 优点:1. 在开发过程的任意时刻,都可以生成一个可以使用,具有一定功能,Bug较少的测试版本 2.

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论