Я пытаюсь использовать Unit Test Html Helper с помощью AutoFixture. Ниже мой SUT
public static MvcHtmlString SampleTable(this HtmlHelper helper,
SampleModel model, IDictionary<string, object> htmlAttributes)
{
if (helper == null)
{
throw new ArgumentNullException("helper");
}
if (model == null)
{
throw new ArgumentNullException("model");
}
TagBuilder tagBuilder = new TagBuilder("table");
tagBuilder.MergeAttributes(htmlAttributes);
tagBuilder.GenerateId(helper.ViewContext.HttpContext.Items[Keys.SomeKey].ToString());
return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal));
}
Как вы можете видеть, он просто возвращает строку MVC Html с табличными тегами и идентификатором, прикрепленным к ней. (Ниже приведен пример Unit Test)
Unit Test с автоскруткой:
[Fact]
public void SampleTableHtmlHelper_WhenKeyExistWithinHttpContext_ReturnsExpectedHtml()
{
var fixture = new Fixture();
//Arrange
fixture.Inject<HttpContextBase>(new FakeHttpContext());
var httpContext = fixture.CreateAnonymous<HttpContextBase>();
fixture.Inject<ViewContext>(new ViewContext());
var vc = fixture.CreateAnonymous<ViewContext>();
vc.HttpContext = httpContext;
vc.HttpContext.Items.Add(Keys.SomeKey, "foo");
fixture.Inject<IViewDataContainer>(new FakeViewDataContainer());
var htmlHelper = fixture.CreateAnonymous<HtmlHelper>();
var sampleModel = fixture.CreateAnonymous<SampleModel>();
//Act
var result = SampleHelpers.SampleTable(htmlHelper, sampleModel, null).ToString();
//Assert
Assert.Equal("<table id=\"foo\"></table>", result);
}
FakeHttpContext и FakeViewDataContainer - это всего лишь фальшивые реализации HttpContextBase и IViewDataContainer.
Этот тест проходит и возвращает ожидаемый результат. Тем не менее, я не уверен, что Im правильно использовал Autofixture здесь. Есть ли лучший способ использовать AutoFixture в этом Unit Test?
Основываясь на частичной информации, трудно точно сказать, как можно было бы уменьшить приведенный выше тест, но я бы предположил, что его можно было бы уменьшить.
Прежде всего, комбинация вызова Inject
, за которой следует CreateAnonymous
, скорее идиоматична, особенно если вы отмените последовательность. Это называется "Замерзание" анонимного значения (и эквивалентно размеру жизненного цикла Single-контейнера DI). Это может быть сказано более кратко:
var vc = fixture.Freeze<ViewContext>();
Также кажется, что тест сопоставляет HttpContext с FakeHttpContext. Сопоставление может быть сделано немного проще, но это будет отображать временные экземпляры...
В любом случае, если у вас нет веских причин использовать Manual Mocks вместо динамической библиотеки Mock, вы также можете решить использовать AutoFixture в качестве самонаводящегося контейнера. Это может избавить вас от большого количества картирования этого типа.
Итак, учитывая все это, я бы предположил, что вы могли бы свести тест к чему-то вроде этого:
[Fact]
public void SampleTableHtmlHelper_WhenKeyExistWithinHttpContext_ReturnsExpectedHtml()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
//Arrange
var vc = fixture.Freeze<ViewContext>();
vc.HttpContext.Items.Add(Keys.SomeKey, "foo");
var htmlHelper = fixture.CreateAnonymous<HtmlHelper>();
var sampleModel = fixture.CreateAnonymous<SampleModel>();
//Act
var result = SampleHelpers.SampleTable(htmlHelper, sampleModel, null).ToString();
//Assert
Assert.Equal("<table id=\"foo\"></table>", result);
}
Однако большая часть части Arrange теперь является чисто декларативной, и поскольку вы, похоже, уже используете xUnit.net, вы можете использовать AutoData Theories for AutoFixture для перемещения большей части переменных в аргументы метода:
[Theory, AutoMoqData]
public void SampleTableHtmlHelper_WhenKeyExistWithinHttpContext_ReturnsExpectedHtml(
[Frozen]ViewContext vc,
HtmlHelper htmlHelper,
SampleModel sampleModel)
{
//Arrange
vc.HttpContext.Items.Add(Keys.SomeKey, "foo");
//Act
var result = SampleHelpers.SampleTable(htmlHelper, sampleModel, null).ToString();
//Assert
Assert.Equal("<table id=\"foo\"></table>", result);
}
Это предполагает, что вы навели AutoMoqCustomization с помощью атрибута AutoDataAttribute следующим образом:
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute :
base(new Fixture().Customize(new AutoMoqCustomization()))
{ }
}
Пожалуйста, имейте в виду, что вам может потребоваться немного изменить приведенный выше код, чтобы он соответствовал деталям вашего API. Это означает только эскиз.