5

我正在尝试对我编写的自定义视图引擎进行单元测试。

视图引擎的预期功能是它在执行 FindView 时改变基本 RazorViewEngine 的外观

这是我的单元测试

public void ViewEngineReturnsDependencyView()
{
    //Mock http request
    var mockRequest = new Mock<HttpRequestBase>();
    //Mock server variable
    NameValueCollection variables = new NameValueCollection();
    variables.Add("APPL_PHYSICAL_PATH", TEST_APPLICATION_PATH);
    mockRequest.Setup(r => r.ServerVariables).Returns(variables);

    //Mock http context
    var mockHttpContext = new Mock<HttpContextBase>();

    //Mock route
    mockHttpContext.Setup(c => c.Request).Returns(mockRequest.Object);
    var routeData = new RouteData();
    routeData.Values.Add("controller", "testController");
    routeData.Values.Add("action", "testAction");

    //Mock controller context
    var controllerContext = new testController().ControllerContext;
    controllerContext.HttpContext = mockHttpContext.Object;
    controllerContext.RouteData = routeData;
    var mockControllerContext = new ControllerContext(mockHttpContext.Object,
                        routeData, 
                        new Mock<ControllerBase>().Object);

    //Run find view
    viewEngine.FindView(mockControllerContext, "TestView", null, false);
}

烦人地viewEngine.FindView(...);抛出一个异常:

测试方法...抛出异常:System.NullReferenceException:对象引用未设置为对象的实例。结果堆栈跟踪:

在 System.Web.WebPages.DisplayModeProvider.GetDisplayMode(HttpContextBase 上下文)

在 System.Web.Mvc.VirtualPathProviderViewEngine.GetPathFromGeneralName(ControllerContext 控制器上下文,列表`1 个位置,字符串名称,字符串控制器名称,字符串 areaName,字符串 cacheKey,字符串 []& 搜索位置)

在 System.Web.Mvc.VirtualPathProviderViewEngine.GetPath(ControllerContext 控制器上下文,字符串 [] 位置,字符串 [] areaLocations,字符串位置属性名称,字符串名称,字符串控制器名称,字符串 cacheKeyPrefix,布尔 useCache,字符串 [] 和搜索位置)

在 System.Web.Mvc.VirtualPathProviderViewEngine.FindView(ControllerContext 控制器上下文,字符串 viewName,字符串 masterName,布尔 useCache)

在 ...Mvc.CustomRazorViewEngine.FindView(ControllerContext controllerContext, String viewName, String masterName, Boolean useCache) 在 ...\Mvc\CustomRazorViewEngine.cs:line 85

在 ...Tests.MVC.ViewEngine.ViewEngineReturnsDependencyView() 在 ...Tests\MVC\ViewEngine.cs:line 78

我的问题是,如何创建适当的模拟来对 RazorViewEngine.FindView() 进行单元测试?

4

2 回答 2

8

System.Web.WebPages.DisplayModeProvider.GetDisplayMode()方法正在使用该HttpContext.Items属性,您还需要模拟该属性。

尝试:

mockHttpContext.Setup(c => c.Items).Returns(new Dictionary<object, object>());
于 2013-10-24T06:47:24.523 回答
2

I know, that I'm possibly late, but I had same problems. After some research I found the way how razor engine was tested by Microsoft team. You can find it here: http://aspnetwebstack.codeplex.com/SourceControl/latest#test/System.Web.Mvc.Test/Test/RazorViewEngineTest.cs The basic idea is to create testable view engine stub, that explicitly exposes protected methods of view engine. ir is called TestableRazorViewEngine and you can find it at the end of the file. I changed it a bit corresponding to my needs. I added 3-rd argument to every stub view engine's method of type ControllerContext to pass controller metadata to my view engine. This is the way how I did it:

[Fact]
public void CreatePartialView_ViewNameWithoutReplacementToken_ReturnsOriginalPath()
{
    var engine = new TestableViewEngine();
    var view = (RazorView)engine.CreatePartialView("partial path", new ControllerContext());
    Assert.Equals("partial path", view.ViewPath);
}

[Fact]
public void CreatePartialView_ViewNameWithReplacementToken_ReturnsViewWithTokenReplacedByControllerNamespace()
{
    var engine = new TestableViewEngine();
    var controller = new DummyController();
    var controllerContext = new ControllerContext { Controller = controller };
    var view = (RazorView)engine.CreatePartialView("partial path %1", controllerContext);
    Assert.Equals("partial path Stub/Tests/Controllers", view.ViewPath);
}
于 2014-09-08T13:39:14.147 回答