针对NUnit的InlineAutoDataAttribute(用于TestCase和TestCaseSource)

7
简而言之:
class AutoMoqDataAttribute : AutoDataAttribute
{
    public AutoMoqDataAttribute() : base(new Fixture().Customize(new AutoMoqCustomization()))
    {
    }
}

public interface IWeapon { bool LaunchAtEarth(double probabilityOfHitting); }

public class DeathStar
{
    readonly IWeapon _weapon;

    public DeathStar(IWeapon weapon) // guard clause omitted for brevity
    {
        this._weapon = weapon;
    }

    public bool FireFromOrbit(double probabilityOfHitting)
    {
        return this._weapon.LaunchAtEarth(probabilityOfHitting);
    }
}

// Make me pass, pretty please with a cherry on the top
[Test, AutoMoqData]
[TestCase(0.1), TestCase(0.5), TestCase(1)]
public void AutoMoqData_should_fill_rest_of_arguments_that_are_not_filled_by_TestCase(
    double probabilityOfHitting,
    [Frozen] Mock<IWeapon> weapon,
    DeathStar platform)
{
    Assert.That(weapon, Is.Not.Null);
    Assert.That(platform, Is.Not.Null);
} // Ignored with error: Wrong number of parameters specified.

// Make me pass, too!
[Test, AutoMoqData]
[TestCaseSource("GetTestCases")]
public void AutoMoqData_should_fill_rest_method_arguments_that_are_not_filled_by_TestCaseSource(
    double probabilityOfHitting,
    [Frozen] Mock<IWeapon> weapon,
    DeathStar platform)
{
    Assert.That(weapon, Is.Not.Null);
    Assert.That(platform, Is.Not.Null);
} // Ignored with error: Wrong number of parameters specified.

IEnumerable<TestCaseData> GetTestCases()
{
    yield return new TestCaseData(0.1);
    yield return new TestCaseData(0.5);
    yield return new TestCaseData(1);
}

这似乎是Xunit的技巧: http://nikosbaxevanis.com/blog/2011/08/25/combining-data-theories-in-autofixture-dot-xunit-extension/ 我找不到NUnit的等效内容。
这个:http://gertjvr.wordpress.com/2013/08/29/my-first-open-source-contribution/ 似乎已经在AutoFixture.NUnit2的当前版本中工作(AutoData属性),但它不能处理当我想让它使用params object[]时的情况,以便测试方法中的第一个参数使用属性参数填充,其余参数通过AutoData属性传递。
有人可以指导我朝着正确的方向吗? 似乎有些东西我无法理解。

AutoFixture.xUnit.net和AutoFixture.NUnit2具有类似的类型名称,但它们建立在不同的对象模型之上。- 看起来您需要一个类似于InlineAutoDataAttributeTestCaseAutoDataAttribute - Nikos Baxevanis
这正是我想要的,但是找不到。 - Raif Atef
2个回答

3
OP的代码这里在nunit2.6.3中对我没有起作用。实际上,它甚至无法编译,不确定nunit基础设施是否已更改。结果是我错过了nunit.core.dll的引用,在添加后,它就编译了。但我使用了自己的实现。
所以我自己实现了一个。实现方式如下:我们将向AutoFixture请求参数,它将提供测试方法所需的所有参数,然后我们只需覆盖我们需要的参数值即可。
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class InlineAutoDataAttribute : AutoDataAttribute
{
    private readonly object[] values;
    public InlineAutoDataAttribute(params object[] values)
        : base(new Fixture().Customize(new AutoMoqCustomization()))
    {
        this.values = values;
    }

    public override IEnumerable<object[]> GetData(MethodInfo method)
    {
        var testCaseData = base.GetData(method);

        foreach (object[] caseValues in testCaseData)
        {
            if (values.Length > caseValues.Length)
            {
                throw new InvalidOperationException("Number of parameters provided is more than expected parameter count");
            }
            Array.Copy(values, caseValues, values.Length);

            yield return caseValues;
        }
    }
}

如何使用:
[Test]
[InlineAutoData(1, 2)]
[InlineAutoData(3, 4)]
public void Whatever_Test_Name(int param1, int param2, TemplateOrder sut)
{
    //Your test here
    Assert.That(sut, Is.Not.Null);
}

测试将被调用

param1 = 1, param2 = 2, sut = given by auto fixture
param1 = 3, param2 = 4, sut = given by auto fixture

你可以认为这个实现不够高效,但至少它能按照预期工作。我也联系过AutoFixture的创建者Mark Seemann,但他似乎也无法帮助我解决问题。所以目前我只能暂时使用这个实现。

其实,我并不是不想帮忙,而是不能轻易地这么做。整个 NUnit 集成已经作为一个拉取请求提交给了 AutoFixture,而自从 2005 年以来我就没有使用过 NUnit,对于整个生态系统的运作方式了解甚少。 - Mark Seemann
@MarkSeemann 不要误解我的意思。我并没有说你不想帮忙。我的意思是你也无法帮忙。如果我的话听起来有误,我很抱歉。我已经修改了它。感谢您的评论。我用一些天真的方法使它工作了。对我来说这很好 :) - Sriram Sakthivel
没关系 - 我主要是想为那些可能在未来看到这个评论但没有上下文的人留下评论 :) - Mark Seemann

2

我已经使它工作了。

不幸的是,在NUnit的可扩展性API中,2.6版存在一些设计上的问题(没有办法覆盖或删除任何内置的测试案例提供程序),所以我被迫使用一些反射手段来获取“TestCaseProviders”类中的内部ExtensionCollection实例

TL;DR:这只适用于NUnit 2.6.x。NUnit 3.0不兼容。

如何使用

只需在已使用常规[TestCase]和[TestCaseSource]属性的测试中添加提供的[AutoMoqData]。测试用例参数将首先被填充,其余的测试方法参数将通过AutoFixture处理。您可以更改AutoMoqDataAttribute以使用任何不同的夹具自定义(例如:AutoRhinoMockCustomization)。

如何让ReSharper的测试运行器工作

如果将此添加到外部程序集并在测试项目中引用它,则NUnit将无法看到您的插件(因为它仅查找正在加载的直接测试程序集或当前运行的测试运行器可执行文件中“addins”子文件夹中的DLL)。

在这种情况下,只需在当前测试项目中创建一个空类,并使其继承AutoMoqDataAddIn。使用ReSharper单元测试运行器进行测试,它会正确地查看测试用例并仅使用“real”测试参数自动生成测试用例名称。

展示代码!

GitHub:https://gist.github.com/rwasef1830/ab6353b43bfb6549b396


这是Autofixture和NUnit的一个有用功能。你能否向AutoFixture.NUnit2包提交pull-request? - sgnsajgon
@sgnsajgon 这里有几个问题,阻止了它成为可拉取请求的内容...使用反射的方式很丑陋,而且一些单元测试运行器(如Resharper)会产生奇怪的副作用,每次运行时都会多次显示“已忽略”的测试。说实话,我现在没有时间去解决这个问题。如果有人想接手并继续开发,可以随意。 - Raif Atef
这个能在nunit 2.6.3上运行吗?你的gist在我的nunit 2.6.3上无法编译。ExtensionsCollection,TestCaseParameterProvider等不存在:( 我是不是漏了什么?现在autofixture是否以任何形式支持此功能? - Sriram Sakthivel
添加一个对nunit.core的引用(不仅仅是nunit.framework)。我认为它在nunit运行器NuGet包中。我不认为autofixture为此提供了支持。 - Raif Atef
@RaifAtef 如果你指的是 nunit.core.interfaces dll,是的,我也已经添加了,但没有成功:( 所以我自己实现了并在下面发布了答案。 - Sriram Sakthivel
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接