2

我正在尝试使用 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));
}

如您所见,它只返回一个带有表格标签和 Id 的 MVC Html 字符串。(参见下面的单元测试结果示例)

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

FakeHttpContext 和 FakeViewDataContainer 只是 HttpContextBase 和 IViewDataContainer 的假实现。

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

4

1 回答 1

5

根据部分信息,很难准确地说出上述测试如何进一步减少,但我猜它可能会减少。

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

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 的详细信息。这只是一个草图。

于 2011-09-06T17:40:29.120 回答