5

我正在使用 MVC 3 Preview 1 试用新的 Razor 视图引擎,并且真的很想使用 NUnit/Moq 编写一个简单的单元测试。我还没有看到任何实际完成的例子——尽管它是 Razor 的真正销售功能之一。

因此,如果我有一个控制器,它使用 DBConext 对象(EF4 CTP 代码优先),并且视图会根据在控制器上调用的操作中加载的模型中提供的项目列表呈现下拉列表,我会喜欢能够测试元素是否填充了项目。

这是我的控制器:

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

}

这是我的模型:

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

这是我的观点:

@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>
 }

我到目前为止的测试代码如下:

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

运行测试时,我只是得到一个 NullReferenceException。

欢迎任何想法/指针等。我真的很想让这个工作,这样我将来就可以对我的观点进行 TDD。

提前致谢!

4

2 回答 2

2

我建议完全避免使用 CshtmlViewEngine 类并自己启动 Razor 引擎。我在这里写了一篇关于在 ASPX 之外编译 Razor 视图的博客文章:http: //vibrantcode.com/blog/2010/7/22/using-the-razor-parser-outside-of-aspnet.html

在 MVC3 的 Preview 1 中,Razor 引擎嵌入在 System.Web.Mvc 中并且是公共的 (IIRC),因此您应该能够在 System.Web.Mvc.dll 中找到该帖子/示例中引用的所有类。

编译页面后,只需加载生成的类,传入模拟出来的上下文对象,然后调用 Execute()。因为你有一个页面的 CodeDOM 树(当你使用 Razor 引擎时),你甚至可以调整基类,而不是 System.Web.Mvc.WebViewPage,它继承自一个测试页面基类,让你交换替换上下文对象等。

于 2010-08-14T15:41:26.517 回答
0

我写过关于单元测试 Razor 视图的文章。它很丑陋,而且很讨厌,但它确实有效,我能够对其进行调整,以测试我在所有项目中的所有观点。

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

尽管对于长期存在的项目,我建议等待 MVC 团队制作的测试工具。

于 2011-03-08T22:18:46.767 回答