Unit testing generic htmlHelper methods with nunit

有些话、适合烂在心里 提交于 2019-12-13 15:05:03

问题


I'm new to nUnit and I've been tasked with creating unit tests for some htmlhelper extension methods.

How should I go about creating a unit test for the following method?

    public static MvcHtmlString EnumDropDownListForOrderBy<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, bool orderById, string firstElement = null, object htmlAttributes = null)
    {
        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

        Type enumType = GetNonNullableModelType(metadata);
        IEnumerable<TEnum> values = Enum.GetValues(enumType).Cast<TEnum>();

        IEnumerable<SelectListItem> items = values.Select(value => new SelectListItem()
        {
            Text = value.GetAttributeFrom<DescriptionAttribute>(value.ToString()).Description,
            Value = value.ToString(),
            Selected = value.Equals(metadata.Model)
        });

        IEnumerable<SelectListItem> itemsFiltered = items.Where(e => !string.IsNullOrEmpty(e.Text)).AsEnumerable();

        itemsFiltered = itemsFiltered.OrderBy(e => (orderById ? e.Text : e.Value));

        return htmlHelper.DropDownListFor(
            expression,
            itemsFiltered,
            firstElement,
            htmlAttributes
        );
    }

Any help would be appreciated


回答1:


Below is how you write a Unit Test for this. Note that since you have not specified that you use a Mock object framework I'm going to the poor man technique, which is the hand written stubs and mocks. There is also another helper method if you are using Moq.

It is important to note that, in order to simplify the code execution I have made couple of changes to your extension method, so the test would not fail unexpectedly. Checking for any unexpected behaver is a good defensive programming practice anyway.

Back to the tests.

SUT (System Under Test)

This is how the SUT (System Under Test) looks like and supporting types looks like. (Please feel free to modify to your need accordingly)

public static class MyHtmlHelper
{
    public static MvcHtmlString EnumDropDownListForOrderBy<TModel, TEnum>
         (this HtmlHelper<TModel> htmlHelper, 
        Expression<Func<TModel, TEnum>> expression,
        bool orderById, string firstElement = null, object htmlAttributes = null, 
        Func<ModelMetadata> fromLambFunc = null)
    {
        ModelMetadata metadata =
        ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);    
        Type enumType = GetNonNullableModelType(metadata);
        IEnumerable<TEnum> values = Enum.GetValues(enumType).Cast<TEnum>();

        IEnumerable<SelectListItem> items = 
            values.Select(value => new SelectListItem()
        {
            Text = GetText(value),
            Value = value.ToString(),
            Selected = value.Equals(metadata.Model)
        });

        IEnumerable<SelectListItem> itemsFiltered = 
        items.Where(e => !string.IsNullOrEmpty(e.Text)).AsEnumerable();
        itemsFiltered = itemsFiltered.OrderBy(e => (orderById ? e.Text : e.Value));

        return htmlHelper.DropDownListFor
        (expression, itemsFiltered, firstElement, htmlAttributes);
    }

    private static Type GetNonNullableModelType(ModelMetadata metadata) {
        return typeof (SomeEnum);
    }

    private static string GetText<TEnum>(TEnum value) {
        return value.GetAttributeFrom<DescriptionAttribute>(value.ToString()) != null
            ? value.GetAttributeFrom<DescriptionAttribute>(value.ToString()).Description
            : string.Empty;
    }
}

public static class ExtensionMethodsAttr
{
    public static T GetAttributeFrom<T>(this object instance, string propertyName) 
      where T : Attribute
    {
        var attrType = typeof(T);
        var property = instance.GetType().GetProperty(propertyName);

        return property != null ?
        (T)property.GetCustomAttributes(attrType, false).First() : default(T) ;
    }
}

public enum SomeEnum { A,}

Unit Tests

[TestFixture]
public class HtmlHelperTests
{
    [Test]
    public void EnumDropDownListForOrderBy_InvokeDropDownListFor_ReturnsExpectedSelectItemResult()
    {
        //Arrange
        var expected = "<select id=\"Foo\" name=\"Foo\"></select>";
        var fakeHtmlHelper = CreateHtmlHelperStaticStubs
        (new ViewDataDictionary(new FakeViewModel() {Foo = SomeEnum.A}));
        //var fakeHtmlHelper = CreateHtmlHelperUsingMoq
        (new ViewDataDictionary(new FakeViewModel(){Foo = SomeEnum.A}));

        //Act
        var result = fakeHtmlHelper.EnumDropDownListForOrderBy
        (model => model.Foo, It.IsAny<bool>(), null, null, null);

        //Assert
        Assert.AreEqual(expected, result.ToString());
    }


    private static HtmlHelper<FakeViewModel> 
         CreateHtmlHelperStaticStubs(ViewDataDictionary viewData)
    {
        var stubControllerContext = new ControllerContext(new FakeHttpContext(), new RouteData(), new FakeController());

        var stubViewContext = new ViewContext(stubControllerContext, new FakeView(),
            new ViewDataDictionary(new FakeViewModel() { Foo = SomeEnum.A }),
            new TempDataDictionary(), new TextMessageWriter());

        var fakeViewDataContainer = new FakeViewDataContainer();
        fakeViewDataContainer.ViewData = viewData;

        return new HtmlHelper<FakeViewModel>(stubViewContext, fakeViewDataContainer);
    }

    //Moq version
    private static HtmlHelper<FakeViewModel> 
       CreateHtmlHelperUsingMoq(ViewDataDictionary viewData)
    {
        var stubControllerContext = new Mock<ControllerContext>();
        stubControllerContext.Setup(x => x.HttpContext).Returns(new Mock<HttpContextBase>().Object);
        stubControllerContext.Setup(x => x.RouteData).Returns(new RouteData());
        stubControllerContext.Setup(x => x.Controller).Returns(new Mock<ControllerBase>().Object); ;

        var stubViewContext = new Mock<ViewContext>();
        stubViewContext.Setup(x => x.View).Returns(new Mock<IView>().Object);
        stubViewContext.Setup(x => x.ViewData).Returns(viewData);
        stubViewContext.Setup(x => x.TempData).Returns(new TempDataDictionary());

        var mockViewDataContainer = new Mock<IViewDataContainer>();

        mockViewDataContainer.Setup(v => v.ViewData).Returns(viewData);

        return new HtmlHelper<FakeViewModel>(stubViewContext.Object, mockViewDataContainer.Object);
    }
}   


class FakeHttpContext : HttpContextBase
{
    private Dictionary<object, object> _items = new Dictionary<object, object>();
    public override IDictionary Items { get { return _items; } }
}

class FakeViewDataContainer : IViewDataContainer
{
    private ViewDataDictionary _viewData = new ViewDataDictionary();
    public ViewDataDictionary ViewData { get { return _viewData; } set { _viewData = value; } }
}

class FakeController : Controller { }

class FakeView : IView
{
    public void Render(ViewContext viewContext, System.IO.TextWriter writer)
    {
        throw new NotImplementedException();
    }
}

public class FakeViewModel {
    public SomeEnum Foo { get; set; }
}


来源:https://stackoverflow.com/questions/20498036/unit-testing-generic-htmlhelper-methods-with-nunit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!