【问题标题】:Can Autofixture enumerate all objects given a list of possible values for each property给定每个属性的可能值列表,Autofixture 能否枚举所有对象
【发布时间】:2014-09-12 01:41:07
【问题描述】:

我正在开发一个业务类,它可以根据对象的属性过滤对象。过滤规则有很多,每一个通常都会考虑多个属性。

我开始检查每条规则,提供了它们被过滤的所有对象属性的枚举,但这很快就变得无趣了,我想在“复制粘贴退化”吞噬我的大脑之前解决这个痛苦。

AutoFixture 应该在这种情况下非常有用,但我在 FAQ 或 CheatSheet 中都找不到信息。 Ploeh 的博客 populated lists 看起来很有希望,但对我来说还不够深入。

所以,给定以下类

public class Possibility
{
    public int? aValue {get;set;}
    public int? anotherValue {get;set;}
}

我能否获得Possibility 的列表,其中每个类都包含一个可能的预定义值aValueanotherValue 的枚举?例如,给定值 [null, 10, 20] 对应 aValue[null, 42] 对应 anotherValue,我将返回 6 个 Possibility 实例。

如果不是,我怎么能在为每个对象类型自己编码之外获得这种行为?

【问题讨论】:

  • 会有 3 个 Possibility 实例。
  • 我想更多的是像夫妻一样的枚举-> null,null |空,42 | 10,空 | 10,42 | ...但我想我知道如何修改您建议的 Generator 来做到这一点
  • 您也可以这样做 - 您必须修改 PossibilityCustomization 的内部队列,然后在 Generator 实例中将 Take(3) 替换为 Take(6)

标签: c# tdd autofixture


【解决方案1】:

鉴于问题中的值:

  • null, 10, 20aValue
  • null42--anotherValue

这是使用 AutoFixture 执行此操作的一种方法,使用 Generator<T>

[Fact]
public void CustomizedAutoFixtureTest()
{
    var fixture = new Fixture();
    fixture.Customizations.Add(
        new PossibilityCustomization());

    var possibilities = 
        new Generator<Possibility>(fixture).Take(3);

    // 1st iteration
    // -------------------
    // aValue       | null
    // anotherValue | null 

    // 2nd iteration
    // -------------------
    // aValue       | 10
    // anotherValue | 42

    // 3rd iteration
    // -------------------
    // aValue       | 20
    // anotherValue | (Queue is empty, generated by AutoFixture.)
}

在内部,PossibilityCustomization 使用 Queue 类来提供预定义值 - 当它用完预定义值时,它使用 AutoFixture。

private class PossibilityCustomization : ISpecimenBuilder
{
    private readonly Queue<int?> aValues = 
                 new Queue<int?>(new int?[] { null, 10, 20 });

    private readonly Queue<int?> anotherValues =
                 new Queue<int?>(new int?[] { null, 42 });

    public object Create(object request, ISpecimenContext context)
    {
        var pi = request as PropertyInfo;
        if (pi != null)
        {
            if (pi.Name == "aValue" && aValues.Any())
                return aValues.Dequeue();

            if (pi.Name == "anotherValue" && anotherValues.Any())
                return anotherValues.Dequeue();
        }

        return new NoSpecimen();
    }
}

【讨论】:

  • 整洁!我猜 Autofixture 知道如何通过基于约定的解析(即[ClassName]Customization)找到PossibilityCustomization,但是我如何将一个ISpecimenBuilder 注册到多个类(例如,在继承的情况下)?
  • 您必须修改Create 方法。上面的ISpecimenBuilder 查找属性名称。你可以让它更通用——你也可以让它更具体——你也可以同时使用许多ISpecimenBuilder实例:)
  • 啊,好吧,它不是特定于 Possibility 类的,任何使用生成器创建的类都会通过 Create 调用来获取其属性。感谢您的澄清
  • 可以让它更具体。
【解决方案2】:

AutoFixture 生成 Anonymous Values,因此当您已经有了想要组合的确切值时,它可能不适合该工作。

如果您使用的是 NUnit,则可以改为:

[Test]
public void HowToGetPermutations(
    [Values(null, 10, 20)] int? aValue,
    [Values(null, 42)] int? anotherValue)
{
    // Test and assert
}

这将运行此测试方法六次 - 每个可能的排列运行一次。

这是我希望 xUnit.net 拥有的少数功能之一,但它没有...

【讨论】:

  • 我知道 NUnit 的组合功能,但我从未想过使用它们来逐个测试我的项目。这是个好主意,我想我的恶心感觉只是我不习惯这样做。我会调查的。
猜你喜欢
  • 2020-09-06
  • 2017-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多