强制AutoFixture使用最贪婪的构造函数

Ric*_*chK 23 c# autofixture

我有一个包含多个构造函数的数据类型,我需要AutoFixture来选择最贪婪的(一个参数最多的).默认行为是选择编号最小的构造函数.

作者的博客文章http://blog.ploeh.dk/2009/03/24/HowAutoFixtureCreatesObjects.aspx似乎并不意味着有一种方法可以覆盖这种行为,所以它是否可能,如果是这样,如何?

Mar*_*ann 27

这当然是可能的.

要更改单个类型(MyClass)的策略:

fixture.Customize<MyClass>(c => c.FromFactory(
    new MethodInvoker(
        new GreedyConstructorQuery())));
Run Code Online (Sandbox Code Playgroud)

要全面改变策略:

fixture.Customizations.Add(
    new MethodInvoker(
        new GreedyConstructorQuery()));
Run Code Online (Sandbox Code Playgroud)

然而,事实证明,全面使用GreedyConstructorQuery很可能会出现问题,如下面的代码片段所示.想象一下这个构造函数的类:

public Foo(string name)
{
    this.name = name;
}
Run Code Online (Sandbox Code Playgroud)

此测试将抛出异常:

[Test]
public void GreedyConstructor()
{
    Fixture fixture = new Fixture();
    fixture.Customizations.Add(new MethodInvoker(new GreedyConstructorQuery()));

    Foo foo = fixture.CreateAnonymous<Foo>();
}
Run Code Online (Sandbox Code Playgroud)

抛出的异常是:

Ploeh.AutoFixture.ObjectCreationException:AutoFixture无法从System.SByte*创建实例,很可能是因为它没有公共构造函数,是抽象或非公共类型.

那么关于SByte*的是什么?在Foo中没有SByte*

嗯,是的.通过将MethodInvoker置于Customization中,它将覆盖所有默认创建策略,包括用于字符串的策略.相反,它寻找字符串最贪婪的构造函数,那就是:

public String(sbyte* value, int startIndex, int length, Encoding enc);
Run Code Online (Sandbox Code Playgroud)

还有sbyte*......


用贪婪算法替换适度的构造函数选择算法仍然是可能的,它比我最初意识到的要多一点.

你能做的是:

写一个像这样的小班:

public class GreedyEngineParts : DefaultEngineParts
{
    public override IEnumerator<ISpecimenBuilder> GetEnumerator()
    {
        var iter = base.GetEnumerator();
        while (iter.MoveNext())
        {
            if (iter.Current is MethodInvoker)
                yield return new MethodInvoker(
                    new CompositeMethodQuery(
                        new GreedyConstructorQuery(),
                        new FactoryMethodQuery()));
            else
                yield return iter.Current;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

并创建像这样的Fixture实例:

Fixture fixture = new Fixture(new GreedyEngineParts());
Run Code Online (Sandbox Code Playgroud)

这应该工作.

  • @MarkSeemann,大多数时候应该使用GreedyEngineParts而不是新的MethodInvoker(新的GreedyConstructorQuery).如果是,请更新您的博客http://blog.ploeh.dk/2011/04/19/ConstructorstrategiesforAutoFixture/并将该类添加到AutoFixture (3认同)