摘要: 一、【前言】(1)本文将用到IOC框架Unity,可参照《Unity V3 初步使用 —— 为我的.NET项目从简单三层架构转到IOC做准备》(2)本文的解决方案是基于前述《使用IdleTest进行TDD单元测试驱动开发演练(1)》、《使用IdleTest进行TDD单元测试驱动开发演练(2)》继续编 写的,但是已经将解决方案、项目名称等等改名为了“IdleTest.EFAndMVCDemo”。(3)本文将不再一步一步的记录,只写出重要的步骤并贴出一些关键代码,完整代码请参照 IdleTest中的IdleTest.EFAndMVCDemo.MvcUI项目和IdleTest.EFAndMVCDem
阅读全文
posted @
2013-12-29 16:45 alert(dong) 阅读(169) |
评论 (0) 编辑
摘要: 【前言】1. 有关上篇请参见《使用IdleTest进行TDD单元测试驱动开发演练(1)》,有关本篇用到Entity Framework Code First请参见《使用NuGet助您玩转代码生成数据————Entity Framework 之 Code First》,而用的个人类库参照IdleTest。2. 本文只用了简单的Entity Framework演练单元测试,着重于Testing,而不是实现,并不会涉及事务、效率等问题。3. 回顾上一篇里面讲到的是针对业务层的测试,正如敏捷中厉行的多与用户沟通,在书《C# 测试驱动开发(Professional Test Driven Develop
阅读全文
posted @
2013-11-09 19:37 alert(dong) 阅读(381) |
评论 (0) 编辑
摘要: 【前言】开发工具:Visual Studio 2012测试库:Visual Studio 2012自带的MSTestDI框架:Unity数据持久层:Entity Framework前端UI:ASP.NET MVC 4.0需求:我这里假设只满足两个功能,一个用户注册,另一个则是登陆的功能,借助于一些DDD思想,我将从领域层(或者常说的BLL)开始开发,当然每一层都是采用TDD,按我喜欢的做法就是“接口先行,测试驱动”,不废话,直奔主题吧。有关VS2012的单元测试请参见《VS2012 Unit Test 个人学习汇总(含目录)》有关测试中使用的IdleTest库请参见http://idletes
阅读全文
posted @
2013-11-01 00:24 alert(dong) 阅读(413) |
评论 (3) 编辑
摘要: 首先,给出MSDN相关地址:http://msdn.microsoft.com/en-us/library/Microsoft.VisualStudio.TestTools.UnitTesting.aspx (类库) Verifying Code by Using Unit Tests(介绍)我的IdleTest源码地址:http://idletest.codeplex.com/VS2012单元测试的主要类:Assert、StringAssert、CollectionAssert,具体可参照上述链接的MSDN介绍。单元测试一直都想接触,但是碍于没有那样的工作环境,故只能由自己在业余时间去...
阅读全文
posted @
2013-10-22 18:55 alert(dong) 阅读(926) |
评论 (4) 编辑
摘要: 【1】我的IdleTest源码地址:http://idletest.codeplex.com/【2】IdleTest改动说明:2013年10月份在保持原有功能的情况下对其动了较大的手术,首先将基本的断言方法分离成为接口,以便于扩展,例如现在可以支持切换测试框架(实现IAssertInstance接口,并修改AssertCommon_Editable.cs中的DEFAULT_INSTANCE为新的对象),然后就是增加对xml一些操作的支持。尽管如此,但并不是完全遵循OCP,可以说对扩展开放,对修改适当关闭。体现在AssertCommon_Editable.cs文件,该文件提供了AssertCom
阅读全文
posted @
2013-10-20 21:44 alert(dong) 阅读(403) |
评论 (2) 编辑
摘要: 如题,本文主要作为在VS2012使用Fakes的入门示例,开发工具必须是VS2012或更高版本。关于Fakes的MSDN地址:http://msdn.microsoft.com/en-us/library/hh549175.aspx关于VS2012单元测试的前期文章:1.《在Visual Studio 2012使用单元测试》、2.《VS2012 单元测试之泛型类(Generics Unit Test)》、3.《VS2012 Unit Test —— 我对接口进行单元测试使用的技巧》4.《VS2012 Unit Test(Void, Action, Func) —— 对无返回值、使用Action
阅读全文
posted @
2013-10-06 16:41 alert(dong) 阅读(1223) |
评论 (0) 编辑
摘要: 【提示】1. 阅读文本前希望您具备如下知识:了解单元测试,了解Dynamic,熟悉泛型(协变与逆变)和Lambda,熟悉.NET Framework提供的 Action与Func委托。2.如果您对单元测试无兴趣请止步。3.本文将使用一些我自己的测试公共代码,位于https://idletest.codeplex.com/,此处亦非常欢迎来访。4.关于本人之前单元测试的文章可参阅《在Visual Studio 2012使用单元测试》、《VS2012 单元测试之泛型类(Generics Unit Test)》、《VS2012 Unit Test —— 我对接口进行单元测试使用的技巧》【修改Idle
阅读全文
posted @
2013-09-02 21:52 alert(dong) 阅读(927) |
评论 (2) 编辑
摘要: 【题外话】 对单元测试不熟悉的童鞋可参照我之前写过的两篇博文:《在Visual Studio 2012使用单元测试》、《VS2012 单元测试之泛型类(Generics Unit Test)》。 以下Demo将使用我已写好的一些关于单元测试的类库(已放至 https://idletest.codeplex.com/,其用了大量的匿名方法,同样不熟悉的可参照我上一篇博文《委托的N种写法,你喜欢哪种?》)。【进入正题】 与其说对接口测试还不如说针对抽象测试,也是我个人比较喜欢的编码步骤:编写接口(面向抽象)=>单元测试=>实现。 OK here we go... 首先假设有如下接口..
阅读全文
posted @
2013-08-18 17:34 alert(dong) 阅读(1241) |
评论 (0) 编辑
摘要: 关于单元测试,如果不会用可以参照我的上篇博文————在Visual Studio 2012使用单元测试首先分享一篇博文,[Visual Studio] 开启Visual Studio 2012通过右键菜单创建单元测试(Unit Test)。泛型有两种,一般泛型与类型约束泛型,在对包含泛型的方法进行单元测试中也可以这么分,详情可参阅http://msdn.microsoft.com/en-us/library/vstudio/ms243401.aspx 。从该页面可以知道,关于泛型的单元测试,微软类库(Microsoft.VisualStudio.TestTools.UnitTesting)提供
阅读全文
posted @
2013-07-10 16:19 alert(dong) 阅读(1386) |
评论 (6) 编辑
摘要: 本人之前很少使用单元测试,总觉得平时的工作写得代码够多了,单元测试还要再编码,增加大量工作量,相信不少程序猿也是这么认为吧。但是我认为,在必要的时候正确运用单元测试,可以大大缩短代码的调试时间,正所谓磨刀不误砍柴工,在此建议仍不会单元测试的,还是学一下吧。当然本人在单元测试方面还是菜鸟,无论是鸡蛋鲜花都欢迎。最近公司请微软的人做了一些关于使用VS2012进行单元测试的小培训,小生微做笔记,结合朦胧的记忆,在此自行总结,并分享之。废话少说,先上笔记:1.先写单元测试(依我愚见,应该是接口先行,如果有的话) -> 测试失败 -> 以最小的改动(即编写实际代码)使测试通过(而在VS201
阅读全文
posted @
2013-06-10 15:50 alert(dong) 阅读(1737) |
评论 (5) 编辑
一、【前言】
(1)本文将用到IOC框架Unity,可参照《Unity V3 初步使用 —— 为我的.NET项目从简单三层架构转到IOC做准备》
(2)本文的解决方案是基于前述《使用IdleTest进行TDD单元测试驱动开发演练(1)》、《使用IdleTest进行TDD单元测试驱动开发演练(2)》继续编 写的,但是已经将解决方案、项目名称等等改名为了“IdleTest.EFAndMVCDemo”。
(3)本文将不再一步一步的记录,只写出重要的步骤并贴出一些关键代码,完整代码请参照 IdleTest 中的IdleTest.EFAndMVCDemo.MvcUI项目和IdleTest.EFAndMVCDemo.MvcUITest。
(4)本文关注点是针对ASP.NET MVC中的单元测试,都是较为简单的ASP.NET MVC,很多代码并不适合实际开发,仅供参考。
(5)程序运行仍会有报错,原因是我没有添加相应的View,但是这不是本文关心的,故而项目代码的完善待日后再说了。
(6)虽然本人早在ASP.NET MVC 1.0时代就使用它来开发项目,但却对现在较新的版本了解不多,因而难免有错漏,望各大虾多多批评指正。
(7)虽然说TDD要测试先行,但我觉得这并不适合所有应用程序的开发,例如ASP.NET MVC,我这里就先创建一个ASP.NET MVC项目“IdleTest.EFAndMVCDemo.MvcUI”,并整理项目的结构,添加一个UserController的控制器,然后才创建单元测试项目“IdleTest.EFAndMVCDemo.MvcUITest”,这两个项目也是我提供的源码链接中本文的关注点,最后去完善实现代码。
二、为测试准备相应代码
1. 首先更新了IdleTest相关类,添加了断言方法“ThrowException”,这对无返回值的函数进行单元测试还是蛮有用的,主要就是断言执行该函数是否正确的抛出了异常与否。该方法通过“Assert.Fail”来实现了自定义的断言,如有需要可参考代码如下
ThrowException
2. 两个项目的相关引用程序集以及Fakes程序集如下图所示
3. 在项目“IdleTest.EFAndMVCDemo.MvcUI”编写相应代码便于支持IOC,前面的文中说了,要想达到测试单元,摆脱依赖,IOC是最好的解耦方式,当然这个也要适度使用。
IocContainer
Global.asax
在Global.asax的Application_Start方法中加了一行代码“IocContainer.Register();”,将所有需要注入的类型全局注册到IOC容器,避免每次请求都要注册而影响性能,这也是按照微软提供的模板中的方式来做。
4. 在项目“IdleTest.EFAndMVCDemo.MvcUITest”编写如下代码,便于支持单元测试。
(1)UITestConfig类用于保存测试用到的一些数据,简言之就是把硬编码写在一起,方便维护,假如在后期登陆页面的URL变化后只需修改此类中的值便可以继续运行单元测试。
UITestConfig
(2)ControllerAssert.cs文件中的类“ControllerAssert”提供了对Controller中的ActionResult类型进行断言的两个常用操作方法。其中AssertViewResult方法对返回ViewResult的Action进行测试;AssertRedirectResult则是针对页面重定向相关的Action,其归根结底就是对Action导航到的URL进行断言。
ControllerAssert
(3)ControllerAssert.cs文件中的类“ControllerAssertInstance”继承“AssertInstance”类并override AssertEqual方法,自定义了针对“ContentResult”类型的断言方式,使得AssertCommon中AssertEqual方法均调用该方法(当然前提是先调用“AssertCommon.ResetAssertInsance(new ControllerAssertInstance());”,可参见AdultRoleAttributeTest中的使用)。
ControllerAssertInstance
三、针对Controller的测试
1. UserController编写了两个构造函数,代码如下,不得不承认这样做更多是为了方便单元测试,感觉有点违背了“不应因单元测试而去修改原代码”的初衷,但是我又没想到其他方式,如您有好的或坏的建议,均盼指点。
UserController构造函数
2. 紧接着编写相应的测试代码,年底了,由于我精力与时间有限,故在此只做了登陆的测试,关于MVC的其他测试思想差不多都大同小异(当然使用ext之类的前端可能不太相同,这不在本文探讨范围)。
UserControllerTest
3. 通过与测试运行相结合去修改UserController,最终的代码如下
UserController
4. 测试通过后,检查覆盖率,如下图所示
四、针对Filter的测试
1. 有关MVC中Filter的好处我这里就不费口舌了,下面我假设这么一个需求,需要对一些页面的访问进行控制,即未成年人不能进入。于是编写以下Filter,这里我将先去实现这个类,然后再进行单元测试。
AdultRoleAttribute
2. 紧接着编写单元测试类AdultRoleAttributeTest,这里编写单元测试有两个难点。第一,AdultRoleAttribute类override OnActionExecuting方法时有一个类型为ActionExecutingContext的参数,我需要通过这个参数获取当前登录用户(“filterContext.HttpContext.User.Identity”),所以要模拟这个依赖有点难度,因为它的成员调用得很深(参见GetHttpContext方法);第二,通过用户名去获取用户的年龄需要依赖于Service层,但这显然不符合单元测试的做法,并且该类难以注入模拟类型(我不想由于单元测试随便去修改原有代码),所以我还得要伪装IocContainer的Instance方法(参见ShimGetUserModel方法)。
AdultRoleAttributeTest
3. 运行覆盖率分析,如下图所示
五、总结
1. 由于UI是与End Users关联最大的,也是项目其他人员极其关心的,因而我仍将单元测试命名为业务或需求人员能看得懂的命名并将各个方法细分到一个或一种用例,与业务或需求人员确定需求(当然有时候这个需要以文档为据,但我这里也是相对的说法,千万别照搬),当需求变更,首先更改的是单元测试,然后再去编写实现代码。还是那句话前期工作量巨大,但是质量保证真的是杠杠的,且在后期修改代码时大大降低风险。
2. 这里的单元测试只是针对UI,并可通过对接口的模拟摆脱了对服务层和仓储层的依赖,然后使用构造函数注入方式实现了DI,而遵循里氏替换原则编写了AssertInstance的子类ControllerAssertInstance,不然(不遵循里氏替换原则继承AssertInstance)将很容易导致IdleTest不能正常工作。也就是说在做TDD时,遵循SOLID的程度与编写单元测试的容易度成正比关系。
3. 如您对ASP.NET MVC 的 TDD感兴趣,可参照MSDN有比较官方的例子(我只找到了VS2010的例子,那时还没有Fakes要自己编写模拟代码,如您找到了VS2012/2013的例子请告诉我一声,不尽感激)。
4. 我这里只是个人学习以及使用单元测试过程中的一些方式、心得等等,肯定存在不足之处,请各位大虾多多指教,同时作为一个菜鸟,也期待能和对设计模式、单元测试、敏捷开发感兴趣的猿/媛友们多多交流共同进步。
5. 完整代码
【废话一段】这算是我2013最后一篇博文了吧,不管认识的不认识的,码农或非码农的,单身的成对的或者搞小三小四的,均祝大家新年快乐!存款多多,股票节节攀升,贵金属重演两年前的大跃进,保险打水漂!家人健康,小孩越来越懂事,老婆越来越漂亮,老公越来越能干!!
给了大家这么多祝福,也希望大家在年后有啥缺人的情况喊我一声。