|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
实不相瞒,net网页编程是我见过的执行效率最低的程序设计语言,前不久在CSDN论坛上有个评测,计算9999的阶乘,同样的循环算法,net网页编程的耗时是.NET的5倍。 本文出自:http://www.ckuyun.com/JeffreyZhao/archive/2009/03/09/no-dependency-to-httpcontext.html
我们持续《ASP.NETMVC单位测试最好理论》,明天次要议论HttpContext的依附成绩。
在ASP.NET中举行单位测试的天敌即是HttpContext,它是ASP.NET的中心,极度庞大,却没法举行Mock1——可见微软可以写出那末复杂的ASP.NET框架真不那末简单。如今这个情况改良了很多,因而人人已可使用System.Web.Abstractions.dll了,这个程序会合供应了关于HttpContext的笼统,也就是HttpContextBase笼统类。因而在ASP.NETMVC中,各类组件均依附于HttpContextBase而不是HttpContext。这是一个优异的做法,人人今后能够尽量地挣脱HttpContext了。
不外这仿佛又是一个悖论。固然已能够对HttpContext举行Mock(这点加强了可测试性),可是过分依附HttpContext关于单位测试来讲也是一个危险。这是HttpContext对象的天分而至:它其实太庞大了。您应当已发觉到,这是个集万千溺爱于一身的对象,从哀求,复兴,使用程序,缓存……几近包括了Web使用程序必要的一切信息。假如要测试一个依附于HttpContext的办法,您必将要为HttpContext的Mock对象添补各类信息——其庞大水平视营业而定。并且,Mock存眷的是“举动”,也就是说它存眷的是做一件事变所利用“路径”。那末假如做一件事变能够接纳多个路径又会如何?是不是必要在测试之前筹办好一切的路径,而且考证被测试的代码“接纳了,并仅仅接纳了个中一条路径”?因而,Stub渐渐进进人们的视野。Stub存眷的是“形态”……这就是另外一个话题了,还会触及到接纳Record&Replay仍是Arrange-Act-Assert体例来举行单位测试,临时不提。
之前谈到对视图举行单位测试时,老赵已经谈起在视图中应当只利用ViewData中的数据。这不是第一次提及要保持HttpContext了,自从有了“笼统”这一有益兵器后,统统“反面谐”要素都可以被分别。试想在MVP形式中,View和Presenter都利用各自的笼统举行交互,统统Web控件,HttpContext等对象都不复存在了,人人眼中只要“数据”和“模子”。一样,在ASP.NETMVC的Action办法中,也不该该利用HttpContext,这是基于优秀的“可测试性”而思索的。您大概会想,如今的HttpContextBase对象已能够Mock了啊。没错,它切实其实“能够”,可是如许做会引发单位测试代码的收缩,由于测试代码中的相称部分必需存眷在测试数据的筹办,而不是被测试的功效上。关于一个Action办法来讲,它存眷的应当是用户与营业逻辑的交互,而不是“怎样把HTTP哀求转化为可用的数据”。实在说究竟,仍是要“分别存眷点”。
在ASP.NETMVC中卖力“转化数据”的条理为ModelBinder。关于这一点,现有的“示例”多数存眷把Form或QueryString中的数据转化为Action参数上,不外ModelBinder可用的中央实在更多。比方在《最好理论》的代码中,底本AccountController的Delete办法完成以下:- publicActionResultDelete(stringuserName){this.MiddleTier.UserManager.Delete(userName);UriurlReferrer=this.Request.UrlReferrer;returnthis.Redirect(urlReferrer.ToString());}
复制代码 在删除指定对象以后,页面将跳转到UrlReferrer地点中。在下面的代码中,这个值将经由过程会见Request.UrlReferer来取得。这就使您的Action办法与HttpContext发生了依附,因而它的单位测试代码就必要如许编写:- [TestMethod]publicvoidDeleteTest(){stringuserName="jeffz";UriurlReferrer=newUri("http://www.microsoft.com");varmockHttpContext=newMock<HttpContextBase>();mockHttpContext.Setup(c=>c.Request.UrlReferrer).Returns(urlReferrer);varmockController=this.GetMockController();mockController.Setup(c=>c.MiddleTier.UserManager.Delete(userName)).Verifiable();mockController.Object.ControllerContext=newControllerContext(mockHttpContext.Object,newRouteData(),mockController.Object);mockController.Object.Delete(userName)...}
复制代码 在单位测试代码中,我们Mock了一个HttpContextBase对象,让它的Request.UrlReferrer属性前往我们筹办好的对象,再机关一个新的ControllerContext并交给Controller。而假如我们的UrlReferrer可以作为Delete办法的参数,那末单位测试代码就会一会儿复杂良多:- [TestMethod()]publicvoidDeleteTest(){stringuserName="jeffz";UriurlReferrer=newUri("http://www.microsoft.com");varmockController=this.GetMockController();mockController.Setup(c=>c.MiddleTier.UserManager.Delete(userName)).Verifiable();mockController.Object.Delete(userName,urlReferrer)...}
复制代码 有些伴侣大概会问,不就是从Request的UrlReferrer属性中取值吗?我们为何要机关一个ControllerContext,不克不及间接设置Controller对象吗?比方如许就复杂多了:- mockController.Setup(c=>c.Request.UrlReferrer).Returns(urlReferrer);
复制代码 仿佛可行,不外您运转的时分就会发明,框架会抛出非常,说只要接口的成员,或能够override的成员才干够被Mock。没错,Controller的Request属性不是virtual的,没法override。Controller类云云计划是存心的,目标就是限定了可用的路径。试想,假如您Mock了Controller.Request属性,可是程序代码经由过程Controller.HttpContext.Request举行会见又怎样办呢?相似的做法另有对办法重载的计划。一样平常来讲,城市把个中几个办法托付给个中独一的办法,而只要谁人办法是能够被override的。如许在编写测试时,我们唯一的Mock出口便断定了,制止了测试代码过分懂得办法完成的成绩。
回到正题。假如要让Delete办法接urlReferrer受参数,那末我们就要编写ModelBinder相干的组件:- publicclassUrlReferrerModelBinder:IModelBinder{publicobjectBindModel(ControllerContextcontrollerContext,ModelBindingContextbindingContext){returncontrollerContext.HttpContext.Request.UrlReferrer;}}
复制代码 并使其能够间接使用到Action的参数上:- publicclassUrlReferrerAttribute:CustomModelBinderAttribute{privatestaticUrlReferrerModelBinders_modelBinder=newUrlReferrerModelBinder();publicoverrideIModelBinderGetBinder(){returns_modelBinder;}}
复制代码 因而乎,我们的Delete办法即可写为:- publicActionResultDelete(stringuserName,UriurlReferrer){this.MiddleTier.UserManager.Delete(userName);returnthis.Redirect(urlReferrer.ToString());}
复制代码 现在的代码,不管是使用程序仍是框架类库,都必需思索“可测试性”这个请求。比方.NET3.0的WF,因为其可测试性欠安一向为人所诟病。如今我们在编写程序时,要时候扣问本人:“这么做便利测试吗?”思索到这个成绩,大概您就会宁神地做出某些决定了2。
注1:实在仍是能够Mock的。比方Typemock利用Profiler的体例举行间接注进,能够Mock任何成员。不外,假如Moq等框架没法满意您的必要,一样平常即是您的计划有些成绩了。
注2:比方,事实让Action办法前往ActionResult,仍是前往void,并间接经由过程Response输入呢?
我以前很喜欢Serv-U,自从它用net网页编程重写之后我就再也没用过,实在是太慢了,我宁可用IIS搭建FTP,虽然IIS搭建FTP在权限管理上很不灵活。 |
|