2011-09-06 107 views
2

我试图单元测试使用AutoFixture的Html帮助。下面是我的SUT单元测试与AutoFixture的Html帮助

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吗?

回答

5

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

首先,调用Inject后跟CreateAnonymous的组合非常习惯 - 特别是如果您颠倒序列。这被称为Freezing匿名值(并且相当于DI容器的Singleton生命周期范围)。它可以更简洁地说是这样的:

var vc = fixture.Freeze<ViewContext>(); 

它也好像在测试是映射的HttpContext FakeHttpContext。 Mapping can be done a little bit easier,但它会映射瞬态实例...

在任何情况下,除非您有令人信服的理由使用Manual Mocks instead of a dynamic Mock library,否则不妨决定使用AutoFixture as an auto-mocking container。这可能会消除很多类型映射。

因此,鉴于这一切,我会猜测,你也许能测试减少这样的事情:

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

然而,大多数的安排一部分现在是纯粹的声明,以及因为你似乎已经使用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 LIK E本:

public class AutoMoqDataAttribute : AutoDataAttribute 
{ 
    public AutoMoqDataAttribute : 
     base(new Fixture().Customize(new AutoMoqCustomization())) 
    { } 
} 

请记住,你可能需要调整上面的代码位,使其适合您的API的细节。这只是一个草图。

+0

非常好。非常感谢Mark。 – Spock