2012-05-08 11 views
5

Piszę testy specflow za pomocą Watin, dla aplikacji ASP.Net MVC, która używa T4MVC.Używanie tras Asp.Net MVC z aplikacji innych niż web (testy)

Używam adresów URL "magicznych ciągów" w testach, które mi się nie podobają.

[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); 
} 

Chciałbym dużo raczej wykorzystywać moje wyniki T4MVC akcji jak to zrobić w MVC aplikacji, coś takiego ...

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

Moja ToAbsoluteUrl Extension Metoda

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); 
     } 
    } 
} 

Co jest poprawny sposób inicjowania RequestContext i RouteCollection, aby móc generować moje testowe adresy URL?

Obecnie otrzymuję wyjątek NullReferenceException na linii var requestContext = new RequestContext(httpContextBase, RouteTable.Routes.GetRouteData(httpContextBase));. Czy jest to właściwy sposób na dodanie requestContext?

A jeśli jest lepszy sposób na zrobienie ActionResulta (z T4MVC) i naprawienie go pod bezwzględnym adresem URL, poza aplikacją internetową, to jest to, czego naprawdę szukam.

+0

Jaką wersję testową urządzenia używasz w specyfikacji SpecFlow? MsTest, NUnit, czy coś innego? – danludwig

+0

Używam xUnit, czy to ważne? – Brook

+0

Nie, zastanawiałem się, że mogę dostosować moją odpowiedź. Nie jestem pewien, jakie są równoważniki xunit dla [TestClass] i [AssemblyInitialize], ale wyobraź sobie, że nie jest trudno to stwierdzić. – danludwig

Odpowiedz

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)); 
    } 
} 

Konstruktor statyczny ustawia twoje prywatne pola. Wybrałem użycie nowej kolekcji RouteCollection, zamiast używać statycznej właściwości RouteTable.Routes, ale być może będziesz w stanie.

Nie sądzę, aby konstruktory dla HttpRequest i HttpResponse miały znaczenie. Właśnie przeszedłem kilka ciągów, aby je skonstruować, nie rzucając wyjątku. Użyj ich do skonstruowania zupełnie nowego HttpContext (nie używaj HttpContext.Current podczas uruchamiania z xUnit). Następnie można umieścić go w HttpContextWrapper, aby uzyskać odwołanie do HttpContextBase.

Skonstruuj nowy obiekt RequestContext, przekazując podstawowe opakowanie i nową instancję RouteData. Użyj tego, wraz z poprzednim RouteCollection, aby zbudować UrlHelper. Zauważ, że jego metoda działania zwróci ciągi poprzedzone znakiem "/", więc powinieneś to pominąć w naszym ustawieniu aplikacji RootUrl (więc użyj czegoś takiego jak value = "https://develop.site.com" bez końcowego ukośnika).

Pamiętaj, że to nie zadziała dla tras zdefiniowanych w obszarach MVC. W tym celu musisz zarejestrować obszary oprócz wywoływania RegisterRoutes w globalnym asaxie.

+0

To się udało, dzięki. Zmieniłem go, aby używał metody "Zapewnij" zamiast inicjatora typu, ponieważ te mają tendencję do wyrzucania bardzo dziwnych wyjątków, gdy pojawiają się problemy, i biorąc pod uwagę, że jest to odczyt z konfiguracji, może się to zdarzyć. – Brook

+0

Jakim jesteś ratownikiem ... Przez wiele godzin szukałem go w Google –

Powiązane problemy