2010-08-13 12 views
5

J'essaie le nouveau moteur de vue Razor avec MVC 3 Preview 1 et je voudrais vraiment écrire un test unitaire simple en utilisant NUnit/Moq. Je n'ai vu aucun exemple de ce fait en cours - même s'il s'agit de l'une des fonctionnalités de vente réelles sur Razor. Donc, si j'ai un contrôleur qui utilise un objet DBConext (code CTP EF4 en premier) et la vue affiche une liste déroulante basée sur une liste d'éléments fournis dans un modèle chargé dans une action appelée sur le contrôleur , J'aimerais pouvoir tester que l'élément contient des éléments.Pointeurs pour l'écriture d'un test unitaire pour une vue basée sur Razor

Voici mon contrôleur:

public class WeatherReportController : Controller, IWeatherReportController 
{ 
    private IWeatherDb _weatherDb; 

    public WeatherReportController() 
    { 
     this._weatherDb = new WeatherDb(); 
    } 

    public ActionResult Index() 
    { 
     WeatherReportIndexModel model = new WeatherReportIndexModel 
     { 
      Report = new WeatherReport { 
       Username = this.HttpContext.User.Identity.Name, 
       WeatherType = new WeatherType() 
      }, 
      WeatherTypeList = _weatherDb.GetAllWeatherTypes() 
     }; 
     return View(model); 
    } 

} 

Voici mon modèle:

public class WeatherReportIndexModel 
{ 
    private IList<WeatherType> _weatherTypeList = new List<WeatherType>(); 
    public IList<WeatherType> WeatherTypeList { 
     get 
     { 
      return _weatherTypeList; 
     } 
     set 
     { 
      _weatherTypeList = value; 
     } 
    } 

    [DisplayName("Type of Weather")] 
    public IList<SelectListItem> WeatherTypeSelectItemList 
    { 
     get 
     { 
      int id = this.Report.WeatherType == null ? 0 : this.Report.WeatherType.WeatherTypeId; 
      List<SelectListItem> selectListItems = this.WeatherTypeList.Select(weatherType => new SelectListItem 
                        { 
                         Value = weatherType.WeatherTypeId.ToString(), 
                         Text = weatherType.Name, 
                         Selected = weatherType.WeatherTypeId == id 
                        }).ToList(); 
      selectListItems.Insert(0, new SelectListItem { Selected = (this.Report.WeatherType == null), Text = "Select Type of Weather", Value = "0" }); 
      return selectListItems; 
     } 
    } 

    public WeatherReport Report { get; set; } 
} 

Et voici mon avis:

@inherits System.Web.Mvc.WebViewPage<Web.UI.Models.WeatherReportIndexModel> 

@{ 
    View.Title = "Index"; 
    LayoutPage = "~/Views/Shared/_Layout.cshtml"; 
} 

<h2>Index</h2> 


@using (Html.BeginForm()) { 
    <div> 
     <fieldset> 
      <legend>New Weather Report</legend> 
      <div class="editor-label"> 
       @Html.LabelFor(m => m.Report.WeatherType.WeatherTypeId) 
       @Html.DropDownListFor(m => m.Report.WeatherType.WeatherTypeId, Model.WeatherTypeSelectItemList) 
    <input type="submit" value="Log On" /> 
      </div> 
    </fieldset> 
</div> 
} 

Le code de test est à moi est à ce jour comme suit:

[TestFixture] 
public class WeatherReportViewTests 
{ 
    [Test] 
    public void Can_render_weather_report_index_view_correctly() 
    { 

     var mockControllerContext = new Mock<ControllerContext>(); 
     var mockSession = new Mock<HttpSessionStateBase>(); 

     mockControllerContext.Setup(p => p.HttpContext.Request.HttpMethod).Returns("POST"); 
     mockControllerContext.Setup(p => p.HttpContext.Request.UserHostAddress).Returns("1.1.1.1"); 
     mockControllerContext.Setup(p => p.HttpContext.Session).Returns(mockSession.Object); 
     mockControllerContext.Setup(p => p.HttpContext.Request.LogonUserIdentity).Returns(WindowsIdentity.GetCurrent()); 

     var routeData = new RouteData(); 
     routeData.Values.Add("controller", "WeatherReport"); 
     routeData.Values.Add("action", "Index"); 

     var viewEngine = new CshtmlViewEngine(); 
     var view = viewEngine.FindView(mockControllerContext.Object, "Index", "_Layout", false); 
     var viewReponse = view.ToString(); 

     Assert.That(viewReponse, Contains.Substring("Sunny Intervals")); 
    } 
} 

Lors de l'exécution du test, je reçois une exception NullReferenceException.

Toutes les idées/indications, etc. seraient les bienvenues. J'aimerais vraiment que cela fonctionne afin que je puisse faire des TDD sur mon point de vue à l'avenir.

Merci d'avance!

+0

Désolé - il suffit de faire une mise à jour à mon code de test - gratter encore ma tête si :( – dextermixwith

+0

Un peu de chance encore je vous ai trouvé un moyen de rendre cette fonctionnelle s'il vous plaît le partager ... thx –

Répondre

2

Je suggère d'éviter complètement la classe CshtmlViewEngine et de lancer le moteur Razor vous-même. J'ai écrit un blog sur la compilation de vues Razor extérieur de ASPX ici: http://vibrantcode.com/blog/2010/7/22/using-the-razor-parser-outside-of-aspnet.html

Dans Preview 1 de MVC3, le moteur de rasoir est intégré dans System.Web.Mvc et elle est publique (IIRC), vous devriez être en mesure de trouver toutes les classes référencées dans cet article/exemple dans System.Web.Mvc.dll. Une fois que vous avez compilé la page, chargez simplement la classe générée, transmettez les objets de contexte mockés et appelez Execute(). Puisque vous avez une arborescence CodeDOM pour la page (lorsque vous utilisez le moteur Razor), vous pouvez même modifier la classe de base de sorte qu'à la place de System.Web.Mvc.WebViewPage, elle hérite d'une classe de base de page de test qui vous permet échangez des objets de contexte de remplacement, etc.

+4

Merci pour ce - il doesn J'ai l'impression que je devrais être patient et attendre une nouvelle version de Razor – dextermixwith

+0

Je suis d'accord que ce n'est pas tout à fait simple. pourtant, je pense que Razor améliore considérablement la capacité des gens à écrire des harnais de test qui peuvent réellement exécuter une page de vue Razor complète sans jamais charger l'ASP.Net (bien que vous deviez simuler des éléments du framework, comme le contexte HTTP et d'autres choses ASP.Net que votre vue touche). –

+0

Je ne m'attendais pas à avoir besoin de compiler du code en mémoire à la volée pour lancer Razor mais bon sang ça marche. – mfloryan

0

J'ai écrit à propos des tests unitaires des vues Razor. C'est moche et toutes sortes de vilains, mais ça marche et j'ai pu l'adapter pour tester tous mes points de vue dans tous les projets.

http://httputility.com/articles/unit-testing-razor-views.html

Bien que pour des projets à vie longue, je suggère l'attente d'un harnais de test réalisé par l'équipe MVC.