AutoFixture的新手试图让我的头围绕它,我看不到它帮助我

时间:2013-05-09 06:11:03

标签: autofixture

目前,我使用定制的虚假对象,在幕后使用NSubstitute创建实际对象,但随着项目的增长,它变得非常难以维护,所以我试图找到替代方案,我希望AutoFixture能够胜任这项工作。

我阅读了文档并且我很挣扎,因为那里没有文档,我阅读了Mark Seemann撰写的大部分博客文章,包括CheatSheet。

我很难掌握的一件事是如何使用带参数的构造函数创建对象,在我的例子中,我需要将参数传递给CsEmbeddedRazorViewEngine以及HttpRequestBase传递给ControllerContext。

我看到它的方式是我需要创建一个假对象,最后创建一个自定义对象,将它们注入

我也看了NBuilder,在那里传递参数似乎有点微不足道但是我已经听说过关于AutoFixture的好东西,我想尝试一下。 :)

我试图减少虚假物品的数量,所以这里是一个真正的测试,我怎么能用AutoFixture做同样的事情?

[Theory, 
 InlineData("en-US"), 
 InlineData("en-us"), 
 InlineData("en")]
public void Should_return_the_default_path_of_the_view_for_enUS(string language)
{
    // Arrange
    const string EXPECTED_VIEW_PATH = "~/MyAssemblyName/Views/Home/Index.cshtml";

    CsEmbeddedRazorViewEngine engine = CsEmbeddedRazorViewEngineFactory.Create(ASSEMBLY_NAME, VIEW_PATH, string.Empty);

    string[] userLanguage = { language };

    HttpRequestBase request = FakeHttpRequestFactory.Create(userLanguage);

    ControllerContext controllerContext = FakeControllerContextFactory.Create(request);

    // Act
    ViewEngineResult result = engine.FindPartialView(controllerContext, VIEW_NAME, false);

    // Assert
    RazorView razorView = (RazorView)result.View;

    string actualViewPath = razorView.ViewPath;

    actualViewPath.Should().Be(EXPECTED_VIEW_PATH);
}

P.S。我使用xUnit作为我的测试框架,NSubstitute作为我的模拟框架我应该同时安装AutoFixture.Xunit和AutoFixture.AutoNSubstitute吗?

更新:在越来越多地了解它之后,我猜它不适合这项工作,因为我试图用AutoFixture替换我的测试双工厂,而不是用它来设置我的SUT。

由于奇怪的原因,我认为NBuilder正在做同样的事情,而且我认为它们是非常不同的工具。

所以经过一番思考后,我想我会改变我在测试中将方法转换为对象的方法,然后使用AutoFixture创建我的SUT并将测试双打注入其中。

2 个答案:

答案 0 :(得分:4)

注意:我没有CsEmbeddedRazorViewEngine类型和所有其他自定义类型的源代码。

以下是使用AutoFixture编写 的方式:

[Theory]
[InlineAutoWebData("en-US", "about", "~/MyAssemblyName/Views/Home/Index.cshtml")]
[InlineAutoWebData("en-US", "other", "~/MyAssemblyName/Views/Home/Index.cshtml")]
public void Should_return_the_default_path_of_the_view_for_enUS(
    string language, 
    string viewName,
    string expected,
    ControllerContext controllerContext,
    CsEmbeddedRazorViewEngine sut)
{
    var result = sut.FindPartialView(controllerContext, viewName, false);
    var actual = ((RazorView)result.View).ViewPath;

    actual.Should().Be(expected);
}

工作原理

它使用AutoFixture本身以及xUnit.net和NSubstitute的胶水库:

PM> Install-Package AutoFixture.Xunit
PM> Install-Package AutoFixture.AutoNSubstitute

使用InlineAutoWebData,您实际上通过AutoFixture结合内联值和自动生成的数据值 - 还包括使用NSubstitute进行自动模拟。

internal class InlineAutoWebDataAttribute : CompositeDataAttribute
{
    internal InlineAutoWebDataAttribute(params object[] values)
        : base(
            new InlineDataAttribute(values),
            new CompositeDataAttribute(
                new AutoDataAttribute(
                    new Fixture().Customize(
                        new WebModelCustomization()))))
    {
    }
}

<强>说明

您实际上可以将上面的WebModelCustomization自定义替换为AutoNSubstituteCustomization,它可以正常工作。

但是,假设您使用的是ASP.NET MVC 4,则需要使用以下命令自定义Fixture实例:

internal class WebModelCustomization : CompositeCustomization
{
    internal WebModelCustomization()
        : base(
            new MvcCustomization(),
            new AutoNSubstituteCustomization())
    {
    }

    private class MvcCustomization : ICustomization
    {
        public void Customize(IFixture fixture)
        {
            fixture.Customize<ControllerContext>(c => c
                .Without(x => x.DisplayMode));

            // Customize the CsEmbeddedRazorViewEngine type here.
        }
    }
}

进一步阅读

答案 1 :(得分:0)

我最终这样做了。

[Theory,
 InlineData("en-US", "Index", "~/MyAssemblyName/Views/Home/Index.cshtml"),
 InlineData("en-us", "Index", "~/MyAssemblyName/Views/Home/Index.cshtml"),
 InlineData("en", "Index", "~/MyAssemblyName/Views/Home/Index.cshtml")]
public void Should_return_the_default_path_of_the_view(string language, string viewName, string expected)
{
    // Arrange
    CsEmbeddedRazorViewEngine engine = new CsEmbeddedRazorViewEngineFixture();

    ControllerContext controllerContext = FakeControllerContextBuilder.WithLanguage(language).Build();

    // Act
    ViewEngineResult result = engine.FindPartialView(controllerContext, viewName, false);

    // Assert
    string actualViewPath = ((RazorView)result.View).ViewPath;

    actualViewPath.Should().Be(expected);
}

我封装了细节以将我的SUT设置到一个夹具中并使用构建器模式来处理我的假货,我认为它现在可读且非常简单。

虽然AutoFixture看起来很酷,但学习曲线似乎很长,我需要投入足够的时间来理解它,现在,我想清理我的单元测试并使它们更具可读性。 :)