2009-10-03 117 views
1

我有一個擴展方法。任何人都可以幫助我如何用Moq測試這種方法嗎?如何使用URLHelp模擬靜態類中的靜態方法? (Moq)

public static string GetBaseUrl(this UrlHelper urlHelper) 
    { 
     Uri contextUri = new Uri(urlHelper.RequestContext.HttpContext.Request.Url, urlHelper.RequestContext.HttpContext.Request.RawUrl); 
     UriBuilder realmUri = new UriBuilder(contextUri) { Path = urlHelper.RequestContext.HttpContext.Request.ApplicationPath, Query = null, Fragment = null }; 
     string url = realmUri.Uri.AbsoluteUri; 

     if (url.EndsWith("/")) 
     { 
      url = url.Remove(url.Length - 1, 1); 
     } 

     return url; 
    } 

非常感謝。

回答

1

正如TrueWill所指出的那樣,您不能直接在UrlHelper.RequestContext中使用Moq,因爲它不是虛擬的。另一方面,UrlHelper是一個公共類,您可以實例化以用於單元測試。

但是,在某些情況下,您將遇到需要指定HttpContextBase來創建UrlHelper,並且Moq可以幫助您執行此操作。

這裏有一個測試表明,我至少可以寫一個單元測試,調用你的GetBaseUrl沒有拋出任何異常:

[TestMethod] 
public void Test1() 
{ 
    var httpCtxStub = new Mock<HttpContextBase>(); 
    httpCtxStub.SetupGet(x => x.Request).Returns(() => 
     { 
      var reqStub = new Mock<HttpRequestBase>(); 
      reqStub.SetupGet(r => r.RawUrl).Returns("http://foo"); 
      reqStub.SetupGet(r => r.Url).Returns(new Uri("http://foo")); 
      return reqStub.Object; 
     }); 

    var requestCtx = new RequestContext(httpCtxStub.Object, new RouteData()); 
    var urlHelper = new UrlHelper(requestCtx, new RouteCollection()); 

    var result = urlHelper.GetBaseUrl(); 

    // Assert something 
} 

然而,這不是簡單的單元測試編寫和維護,所以我支持TrueWill的評論,如果您將UrlHelper隱藏在界面後面,您可能會使自己的生活變得更簡單。

+0

+1:比我的更好的答案。 – TrueWill

+0

非常感謝。 –

+0

關於使用接口在此播客中使用網關模式來分離依賴關係有一個很好的討論:http://www.slickthought.net/post/2009/04/03/New-Spaghetti-Code-Podcast-ndash3b-Donn -Felker會談,Mocking.aspx – TrueWill

1

UrlHelper.RequestContext屬性是非虛擬的。據我所知,Moq在這種情況下不會有所幫助。

您可以爲UrlHelper創建一個包裝類,它實現了一個接口,但是這看起來會破壞使用擴展方法的目的。

Typemock可能會做你想做的,如果你有商業計劃的預算。 (我沒有嘗試過;我自己使用Moq。)

另一個選擇是用這種方法編寫集成測試;雖然它們的運行速度比單元測試慢,但我懷疑這種方法不太可能經常使用版本。

一個更大的問題是耦合到UrlHelper,從而降低應用程序其餘部分的可測試性。也許其他海報可以建議這個問題的答案。

+0

+1用於暗示將UrlHelper隱藏在界面後面。 –

相關問題