2013-12-10 3 views
3

Я новичок в nUnit, и мне было поручено создавать модульные тесты для некоторых методов расширения htmlhelper.Единичное тестирование общих методов htmlHelper с nunit

Как я могу создать единичный тест для следующего метода?

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

Любая помощь будет оценена

+0

Какие конкретно поведение, которое вы хотите проверить? – Spock

+0

Возможно, просто простой тест, чтобы узнать, можно ли вернуть null? –

+0

Со значением.GetAttributeFrom (значение.ToString()). Описание, значение является общим i.e TEnum. И GetAttributeFrom - это метод расширения wand, который вы указываете для типа genric, который будет использоваться как , где вы указываете TEnum в методе расширения. Можете ли вы скомпилировать этот код. Хорошо, если вы можете публиковать частные методы и любые методы расширения, которые вы используете в своем вопросе. Это дает большую видимость в отношении того, что нужно обрезать/издеваться и т. Д. – Spock

ответ

2

Ниже, как вы пишете юнит-тестов для этого. Обратите внимание, что, поскольку вы не указали, что используете фреймворк Mock, я перехожу к технике бедного человека, которая является hand written stubs and mocks. Существует также другой вспомогательный метод, если вы используете Moq.

Важно отметить, что для упрощения выполнения кода я сделал пару изменений в вашем методе расширения, поэтому тест не завершится неожиданно. Проверка любого неожиданного поведения является хорошей защитной практикой программирования в любом случае.

Назад к тестам.

SUT (System Test Под)

Это как 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,} 

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

Привет, Спок, это здорово! Большое вам спасибо, а также за предоставление альтернативы, которая использует moq. Это очень полезно, и я уверен, что другие найдут это. –

Смежные вопросы