日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
ASP.NETMVC單元測(cè)試:HttpContext類的Path屬性解惑

有關(guān)HttpContext類的Path屬性問題描述

成都創(chuàng)新互聯(lián)公司主營(yíng)白水網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,成都APP應(yīng)用開發(fā),白水h5微信小程序搭建,白水網(wǎng)站營(yíng)銷推廣歡迎白水等地區(qū)企業(yè)咨詢

前一段時(shí)間有朋友在郵件中向我抱怨,說他們團(tuán)隊(duì)在使用ASP.NET MVC開發(fā)時(shí),在單元測(cè)試的時(shí)候總是遇到一些不那么方便的地方。例如,對(duì)于HttpContext中各種千奇百怪的Path總是無(wú)法掌控。例如某個(gè)功能會(huì)用到HttpContext的Path屬性,有的又要用到RawUrl——有的又會(huì)涉及到HostName。于是在單元測(cè)試的時(shí)候,就可能需要填充Mock對(duì)象的多種Path屬性,而這幾種Path屬性的值,在理論上還有關(guān)系。這其實(shí)還是小事,一個(gè)麻煩的事情在于,如果功能實(shí)現(xiàn)的方式變了,例如原本使用RawUrl屬性,而后來忽然覺得應(yīng)該使用CurrentExecutionFilePath比較合適,于是單元測(cè)試就必須跟著改。如此反復(fù),疲于奔命。

就我個(gè)人經(jīng)驗(yàn)看來,這種情況還是蠻常見的,因?yàn)槟承r(shí)候兩種Path屬性的值差不多,看上去都可以正常使用,于是剛開始編寫的時(shí)候可能選擇了其中一個(gè)。但是后來發(fā)現(xiàn),在另一些情況下兩種Path就有區(qū)別了,而且應(yīng)該使用的是另一個(gè)屬性,于是不得不修改,進(jìn)而單元測(cè)試失敗了。于是他問我,有沒有什么好方法來“完整而可靠地”設(shè)置那些繽繁復(fù)雜的Path屬性。我之前其實(shí)也是根據(jù)需求設(shè)置各種Path屬性,但是這的確不好,最重要的問題在于“單元測(cè)試”需要了解太多“被測(cè)試方法”的實(shí)現(xiàn)細(xì)節(jié)了,這種依賴非常的不可靠。雖然這也是Mock對(duì)象被人詬病的特點(diǎn)之一,但是如果我們能夠緩解這個(gè)缺陷自然再好不過了。

不過話說回來,在“應(yīng)對(duì)”這個(gè)問題之前,您要先了解目前的功能是不是真要訪問HttpContext中的各種Path。ASP.NET MVC為了提高程序的可測(cè)試性作了很多努力,或者說,將“關(guān)注點(diǎn)”進(jìn)行了很大程度的分離。在大部分情況下,我們都能夠不去觸及HttpContext,而且我們應(yīng)該盡可能避免這種情況的發(fā)生。例如,對(duì)Controller做單元測(cè)試的時(shí)候直接傳遞參數(shù),為Model Binder做單元測(cè)試的時(shí)候使用ValueProvider。想來想去,會(huì)直接使用到HttpContext的Path屬性的場(chǎng)景不多,可能自定義Route算是一個(gè)吧,因?yàn)樗墓δ芫褪墙馕鯱RL。

HttpContext類的Path屬性原理

HttpContext的Path屬性都是通過HttpRequest對(duì)象獲得的。而事實(shí)上ASP.NET中的HttpRequest對(duì)象已經(jīng)為我們提供一種直接通過URL構(gòu)造的功能:

 
 
 
  1. var request = new HttpRequest(  
  2.     "",                                      /* filename */ 
  3.     "http://www.cnblogs.com/JeffreyZhao/",   /* url */ 
  4.     "hello=world");                          /* querystring */ 

估計(jì)ASP.NET開發(fā)團(tuán)隊(duì)也知道URL是個(gè)難辦的問題,為我們預(yù)留了這樣一個(gè)構(gòu)造函數(shù)。這時(shí)的request對(duì)象會(huì)預(yù)填了大多數(shù)Path相關(guān)的屬性:

 
 
 
  1. request  
  2. {System.Web.HttpRequest}  
  3.     AcceptTypes: null 
  4.     AnonymousID: null 
  5.     ApplicationPath: null 
  6.     AppRelativeCurrentExecutionFilePath: threw an exception of type 'System.NullReferenceException' 
  7.     Browser: null 
  8.     ClientCertificate: threw an exception of type 'System.NullReferenceException' 
  9.     ContentEncoding: threw an exception of type 'System.NullReferenceException' 
  10.     ContentLength: 0  
  11.     ContentType: "" 
  12.     Cookies: {System.Web.HttpCookieCollection}  
  13.     CurrentExecutionFilePath: "/JeffreyZhao/" 
  14.     FilePath: "/JeffreyZhao/" 
  15.     Files: {System.Web.HttpFileCollection}  
  16.     Filter: {System.Web.HttpInputStreamFilterSource}  
  17.     Form: {}  
  18.     Headers: {}  
  19.     HttpMethod: "GET" 
  20.     InputStream: {System.Web.HttpInputStream}  
  21.     IsAuthenticated: threw an exception of type 'System.NullReferenceException' 
  22.     IsLocal: false 
  23.     IsSecureConnection: false 
  24.     LogonUserIdentity: null 
  25.     Params: {hello=world}  
  26.     Path: "/JeffreyZhao/" 
  27.     PathInfo: "" 
  28.     PhysicalApplicationPath: threw an exception of type 'System.ArgumentNullException' 
  29.     PhysicalPath: "" 
  30.     QueryString: {hello=world}  
  31.     RawUrl: "/JeffreyZhao/?hello=world" 
  32.     RequestType: "GET" 
  33.     ServerVariables: {}  
  34.     TotalBytes: 0  
  35.     Url: {http://www.cnblogs.com/JeffreyZhao/}  
  36.     UrlReferrer: null 
  37.     UserAgent: null 
  38.     UserHostAddress: null 
  39.     UserHostName: null 
  40.     UserLanguages: null 

以上內(nèi)容是從Visual Studio的Immediate Window中看到的,由此可以發(fā)現(xiàn),其中大部分的Path屬性已經(jīng)準(zhǔn)備好了,但是AppRelativeCurrentExecutionFilePath屬性拋出異常(還有兩個(gè)與本地磁盤路徑有關(guān)的Path就忽略了),因?yàn)樗枰囟ǖ奶摂M路徑環(huán)境才能計(jì)算出來。通過.NET Reflector觀察這個(gè)屬性的實(shí)現(xiàn),會(huì)發(fā)現(xiàn)其中牽涉到的內(nèi)容不是一點(diǎn)兩點(diǎn),幾乎不可能通過設(shè)置外部環(huán)境的方式來使其通過。因此,我們最終還是要通過Mock框架來進(jìn)行設(shè)置——反正我們也需要設(shè)置HttpRequest的其它屬性,不是嗎?

 
 
 
  1. var realRequest = new HttpRequest(  
  2.     "",                                      /* filename */ 
  3.     "http://www.cnblogs.com/JeffreyZhao/",   /* url */ 
  4.     "hello=world");                          /* querystring */ 
  5. var mockRequest = new Mock(realRequest) { CallBase = true };  
  6. mockRequest  
  7.     .Setup(r => r.AppRelativeCurrentExecutionFilePath)  
  8.     .Returns("~" + realRequest.CurrentExecutionFilePath);  

這里還是使用Moq框架,而Mock的對(duì)象則是HttpRequestWrapper類型,而不是我們常用的HttpRequestBase類型。HttpRequestWrapper的特點(diǎn)便是可以“塞入”一個(gè)真正的HttpRequest對(duì)象,然后把所有成員都委托給這個(gè)HttpRequest對(duì)象。我們?cè)跇?gòu)建一個(gè)Mock對(duì)象之后,還需要把CallBase屬性設(shè)為true,這樣便可以讓Mock對(duì)象在默認(rèn)情況下直接使用Wrapper的實(shí)現(xiàn)了。

有了Request,我們便可以構(gòu)建一個(gè)HttpContext的Mock對(duì)象:

 
 
 
  1. var mockContext = new Mock();  
  2. mockContext.Setup(c => c.Request).Returns(mockRequest.Object);  

但是,Moq框架有個(gè)限制,那就是如果您指定了這里的Request對(duì)象,再去通過HttpContext指定Request中的其他屬性,就會(huì)把原來的HttpRequest對(duì)象給覆蓋。也就是說,下面的代碼會(huì)讓我們對(duì)HttpRequest做的努力付之東流:

 
 
 
  1. mockContext.Setup(c => c.Request.Form).Returns(new NameValueCollection());  

這樣您會(huì)發(fā)現(xiàn),mockContext.Object.Request下除了Form外的其他屬性都沒有值了(或拋出異常,視您Mock時(shí)的Behavior是Loose還是Strict而定)。因此,如果我們希望進(jìn)一步修改HttpRequest中屬性的時(shí)候,只能直接使用那個(gè)Mock對(duì)象進(jìn)行設(shè)置。我不清楚其他Mock框架的行為如何,如果您使用的也是Moq框架,可能就只得這么做了。

為了使用方便,我也在測(cè)試項(xiàng)目中準(zhǔn)備了這樣一個(gè)輔助方法:

 
 
 
  1. public static class MockHelper  
  2. {  
  3.     public static Mock MockRequest(string url, out Mock mockRequest)  
  4.     {  
  5.         int index = url.IndexOf('?');  
  6.         string path = index >= 0 ? url.Substring(0, index) : url;  
  7.         string queryString = index >= 0 ? url.Substring(index + 1) : "";  
  8.  
  9.         var realRequest = new HttpRequest("", path, queryString);  
  10.         mockRequest = new Mock(realRequest) { CallBase = true };  
  11.         mockRequest  
  12.             .Setup(r => r.AppRelativeCurrentExecutionFilePath)  
  13.             .Returns("~" + realRequest.CurrentExecutionFilePath);  
  14.  
  15.         var mockContext = new Mock();  
  16.         mockContext.Setup(c => c.Request).Returns(mockRequest.Object);  
  17.         return mockContext;  
  18.     }  
  19. }  
  20.  

于是我們就可以更方便地進(jìn)行相關(guān)的單元測(cè)試。例如,我們“象征性”地測(cè)試一下ASP.NET Routing中內(nèi)置的Route類型:

 
 
 
  1. [Fact]  
  2. public void URL_Capturing_and_Generation()  
  3. {  
  4.     // prepare route  
  5.     Route route = new Route("{controller}/{action}/{id}"null);  
  6.  
  7.     // Mock request  
  8.     string url = "http://www.cnblogs.com/Home/Index/5";  
  9.     Mock mockRequest;  
  10.     var mockContext = MockHelper.MockRequest(url, out mockRequest);  
  11.     mockContext.Setup(c => c.Response.Charset).Returns("utf-8"); // if you need  
  12.  
  13.     // test data capturing  
  14.     RouteData routeData = route.GetRouteData(mockContext.Object);  
  15.     Assert.Equal("Home", routeData.GetRequiredString("controller"));  
  16.     Assert.Equal("Index", routeData.GetRequiredString("action"));  
  17.     Assert.Equal("5", routeData.GetRequiredString("id"));  
  18.  
  19.     // test url generation  
  20.     var hash = new { controller = "Account", action = "List", id = 1};  
  21.     var values = new RouteValueDictionary(hash);  
  22.     var requestContext = new RequestContext(mockContext.Object, routeData);  
  23.     var pathData = route.GetVirtualPath(requestContext, values);  
  24.     Assert.Equal("Account/List/1", pathData.VirtualPath);  
  25. }  
  26.  

具體內(nèi)容就敘述到這里,目前Path相關(guān)的問題應(yīng)該已經(jīng)不會(huì)給您造成太大問題了。

以上就是對(duì)HttpContext類的Path屬性的問題解惑。本文來自老趙點(diǎn)滴:《在單元測(cè)試時(shí)指定HttpContext的各種Path》

【編輯推薦】

  1. 自定義的ControllerFactory:接口實(shí)現(xiàn),支持Area
  2. ASP.NET Routing之“解析URL”功能詳解
  3. 為ASP.NET MVC應(yīng)用添加自定義路由
  4. 學(xué)習(xí)ASP.NET MVC路由的使用方法
  5. 淺析ASP.NET中的URL Rewrite

名稱欄目:ASP.NETMVC單元測(cè)試:HttpContext類的Path屬性解惑
當(dāng)前URL:http://m.5511xx.com/article/cdopspi.html