使用nunit对通用htmlHelper方法进行单元测试

时间:2013-12-10 15:11:48

标签: unit-testing model-view-controller nunit html-helper

我是nUnit的新手,我的任务是为一些htmlhelper扩展方法创建单元测试。

我应该如何为以下方法创建单元测试?

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

任何帮助将不胜感激

1 个答案:

答案 0 :(得分:2)

下面是你为此编写单元测试的方法。请注意,既然您没有指定使用Mock对象框架,那么我将使用穷人技术,即hand written stubs and mocks。如果您使用Moq,还有另一种辅助方法。

重要的是要注意,为了简化代码执行,我对扩展方法进行了一些更改,因此测试不会意外地失败。无论如何,检查任何意外行为都是一种很好的防御性编程实践。

回到测试。

SUT(受测试系统)

这就是SUT(被测系统)的样子和支持类型的样子。 (请随意修改您的需求)

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

单元测试

[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; }
}
相关问题