单元使用AutoFixture测试Html Helper

Spo*_*ock 2 c# model-view-controller unit-testing autofixture

我正在尝试使用AutoFixture对Html Helper进行单元测试.以下是我的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));
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,它只返回一个带有表标签的MVC Html字符串,并附加了Id.(参见下面的单元测试结果示例)

使用AutoFixture进行单元测试:

[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);
}      
Run Code Online (Sandbox Code Playgroud)

FakeHttpContext和FakeViewDataContainer只是HttpContextBase和IViewDataContainer的虚假实现.

此测试通过并返回预期结果.但是,我不确定我是否正确使用了Autofixture.有没有更好的方法在单元测试中使用AutoFixture?

Mar*_*ann 5

基于部分信息,很难准确地说明上述测试如何进一步减少,但我猜它可以减少.

首先,Inject后面的调用组合CreateAnonymous是相当惯用的 - 特别是如果你颠倒序列.这称为冻结匿名值(相当于DI容器的Singleton生命周期范围).可以这样说得更简洁:

var vc = fixture.Freeze<ViewContext>();
Run Code Online (Sandbox Code Playgroud)

似乎测试将HttpContext映射到FakeHttpContext.映射可以更容易一些,但这将映射Transient实例...

在任何情况下,除非您有令人信服的理由使用手动模拟而不是动态模拟库,否则您可能决定使用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);
}
Run Code Online (Sandbox Code Playgroud)

但是,大多数编配部分现在纯粹是声明性的,并且由于您似乎已经在使用xUnit.net,因此可以使用AutoFixture的AutoData理论将大多数变量移动到方法参数:

[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);
}
Run Code Online (Sandbox Code Playgroud)

这假设您已将AutoMoqCustomization与AutoDataAttribute桥接,如下所示:

public class AutoMoqDataAttribute : AutoDataAttribute
{
    public AutoMoqDataAttribute :
        base(new Fixture().Customize(new AutoMoqCustomization()))
    { }
}
Run Code Online (Sandbox Code Playgroud)

请注意,您可能需要稍微调整上述代码,以使其符合API的详细信息.这仅仅是一个草图.