2012-05-08 80 views
5

我正在使用Watin編寫使用T4MVC的Asp.Net MVC應用程序的specflow測試。從非web應用程序使用Asp.Net MVC路由(測試)

我發現自己在測試中使用了「魔術字符串」網址,我不喜歡它。

[Given(@"I am on the sign up page")] 
public void GivenIAmOnTheSignUpPage() 
{ 
    string rootUrl = ConfigurationManager.AppSettings["RootUrl"]; 
    string fullUrl = string.Format("{0}/Authentication/Signup",rootUrl); 
    WebBrowser.Current.GoTo(fullUrl); 
} 

我寧願用我的行動T4MVC結果就像我在MVC應用程序做的,這樣的事情...

[Given(@"I am on the sign up page")] 
public void GivenIAmOnTheSignUpPage() 
{ 
    WebBrowser.Current.GoTo(MVC.Authentication.SignUp().ToAbsoluteUrl()); 
} 

ToAbsoluteUrl擴展方法

public static class RouteHelper 
{ 
    private static UrlHelper _urlHelper; 
    private static string _rootUrl; 

    public static string ToAbsoluteUrl(this ActionResult result) 
    { 
     EnsureUrlHelperInitialized(); 

     var relativeUrl = _urlHelper.Action(result); 
     return string.Format("{0}/{1}", _rootUrl, relativeUrl); 
    } 

    private static void EnsureUrlHelperInitialized() 
    { 
     if (_urlHelper==null) 
     { 
      _rootUrl = ConfigurationManager.AppSettings["RootUrl"]; 

      var request = new HttpRequest("/", _rootUrl, ""); 
      var response = new HttpResponse(new StringWriter()); 
      var context = new HttpContext(request,response); 
      HttpContext.Current = context; 
      var httpContextBase = new HttpContextWrapper(context); 


      RouteTable.Routes.Clear(); 
      MvcApplication.RegisterRoutes(RouteTable.Routes); 

      var requestContext = new RequestContext(httpContextBase, RouteTable.Routes.GetRouteData(httpContextBase)); 

      _urlHelper = new UrlHelper(requestContext, RouteTable.Routes); 
     } 
    } 
} 

是什麼初始化RequestContext和RouteCollection的正確方法,以便我可以生成我的測試URL?

當前我收到一條NullReferenceException對var requestContext = new RequestContext(httpContextBase, RouteTable.Routes.GetRouteData(httpContextBase));行。這是新的一個requestContext的正確方法嗎?

或者,如果有一個更好的方法可以將ActionResult(來自T4MVC)並將其解析爲絕對網址,而不是網絡應用程序,那真的是我正在尋找的。

+0

你使用什麼單元測試庫與SpecFlow? MsTest,NUnit還是別的? – danludwig

+0

我正在使用xUnit,這很重要嗎? – Brook

+0

不,我想知道,所以我可以自定義我的答案。我不確定[TestClass]和[AssemblyInitialize]的xunit等價物是什麼,但想象一下它不難發現。 – danludwig

回答

5
public static class RouteHelper 
{ 
    private static UrlHelper _urlHelper; 
    private static string _rootUrl; 

    static RouteHelper() 
    { 
     var routes = new RouteCollection(); 
     MvcApplication.RegisterRoutes(routes); 
     var req = new HttpRequest(string.Empty, "http://www.site.com", null); 
     var res = new HttpResponse(null); 
     var ctx = new HttpContext(req, res); // do not use HttpContext.Current 
     var requestContext = new RequestContext(new HttpContextWrapper(ctx), 
      new RouteData()); 
     _urlHelper = new UrlHelper(requestContext, routes); 
     _rootUrl = ConfigurationManager.AppSettings["RootUrl"]; 
    } 

    public static string ToAbsoluteUrl(this ActionResult result) 
    { 
     return string.Format("{0}{1}", _rootUrl, _urlHelper.Action(result)); 
    } 
} 

靜態構造函數設置您的私有字段。我選擇使用一個新的RouteCollection,而不是使用靜態RouteTable.Routes屬性,但您可能可以。

我不認爲HttpRequest和HttpResponse的構造函數很重要。我只是通過一些字符串來讓它們構造而不拋出異常。使用這些來構建全新的HttpContext(從xUnit運行時不要使用HttpContext.Current)。然後你可以把它放到一個HttpContextWrapper中來獲取你的HttpContextBase引用。

構建一個新的RequestContext,傳入您的基本包裝器和一個新的RouteData實例。使用它和你以前的RouteCollection一起構造UrlHelper。請注意,它的Action方法將返回前綴爲「/」的字符串,因此您應該將其從RootUrl appSetting中刪除(因此請使用類似value =「https://develop.site.com」的內容,而不使用尾部斜槓)。

注意這不適用於在MVC區域中定義的路由。爲此,除了在全局asax中調用RegisterRoutes之外,還需要註冊這些區域。

+0

這樣做,謝謝。雖然我確實改變了它,但是使用「Ensure」方法而不是類型初始化方法,因爲這些方法在出現問題時往往會拋出非常奇怪的異常,並且假設這是從配置中讀取的,那很可能會發生。 – Brook

+0

你是一個救生員..我爲此搜索了好幾個小時 –