Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I am trying to test some HtmlHelper extension methods I have written. My first problem was how to create a HtmlHelper instance, but I solved that using this code:

private static HtmlHelper<T> CreateHtmlHelper<T>(T model)
{
    var viewDataDictionary = new ViewDataDictionary(model);
    var controllerContext = new ControllerContext(new Mock<HttpContextBase>().Object,
    new RouteData(),
    new Mock<ControllerBase>().Object);

    var viewContext = new ViewContext(controllerContext, new Mock<IView>().Object, viewDataDictionary, new TempDataDictionary(), new Mock<TextWriter>().Object);

    var mockViewDataContainer = new Mock<IViewDataContainer>();
mockViewDataContainer.Setup(v => v.ViewData).Returns(viewDataDictionary);

    return new HtmlHelper<T>(viewContext, mockViewDataContainer.Object);
}

Several of my tests now work fine, but there is one test that throws an exception. The test is defined as follows:

// Arrange
var inputDictionary = CreateDictionary();
var htmlHelper = CreateHtmlHelper(inputDictionary);

// Act
var actualHtmlString = htmlHelper.EditorFor(m => m.Dict, model).ToHtmlString();
...

The EditorFor method is my extension method. Somewhere in that method, the following call is made:

tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(expression, metadata));    

It is that when this code is executed from my unit test that the following exception is thrown:

System.NullReferenceExceptionObject reference not set to an instance of an object.
   at System.Web.Mvc.ViewContext.ScopeCache.Get(IDictionary`2?scope,?HttpContextBase?httpContext)
   at System.Web.Mvc.ViewContext.get_UnobtrusiveJavaScriptEnabled()
   at System.Web.Mvc.HtmlHelper.GetUnobtrusiveValidationAttributes(String?name,?ModelMetadata?metadata)
   at AspNetMvcDictionarySerialization.HtmlHelperExtensions.InputTagHelper(HtmlHelper?htmlHelper,?ModelMetadata?metadata,?InputType?inputType,?String?expression,?IDictionary`2?htmlAttributes,?String?fullName,?Int32?index,?String?fieldType,?String?val) in HtmlHelperExtensions.cs: line 154

So the code fails in ScopeCache.Get, but why? Does anyone have any idea how to solve this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
298 views
Welcome To Ask or Share your Answers For Others

1 Answer

What I ended up doing was looking at the source code of ASP.NET MVC. In their code, they also test HtmlHelper instances. They do so using a utility class named MvcHelper, which provides convenience methods to create new HtmlHelper instance with a correctly prepared HTTP context.

After removing the code I did not need, I ended up with the following class:

public static class MvcHelper
{
    public static HtmlHelper<TModel> GetHtmlHelper<TModel>(TModel inputDictionary)
    {
        var viewData = new ViewDataDictionary<TModel>(inputDictionary);
        var mockViewContext = new Mock<ViewContext> { CallBase = true };
        mockViewContext.Setup(c => c.ViewData).Returns(viewData);
        mockViewContext.Setup(c => c.HttpContext.Items).Returns(new Hashtable());

        return new HtmlHelper<TModel>(mockViewContext.Object, GetViewDataContainer(viewData));
    }

    public static IViewDataContainer GetViewDataContainer(ViewDataDictionary viewData)
    {
        var mockContainer = new Mock<IViewDataContainer>();
        mockContainer.Setup(c => c.ViewData).Returns(viewData);
        return mockContainer.Object;
    }
}

With this helper class, my code executed correctly.

I have created a gist for the complete helper class to allow for easy inclusion in your project: https://gist.github.com/ErikSchierboom/6da474dcd5751fbbc94c


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...