使用autofixture创建结构不会引发公共构造函数错误

Rok*_*Rok 8 c# unit-testing autofixture

我有一个结构,例如:

public struct Foo
{
    public int Bar;
    public string Baz;
}
Run Code Online (Sandbox Code Playgroud)

并希望使用自动混合在我的单元测试中创建它.我尝试使用以下内容:

IFixture fixture = new Fixture();
var f = fixture.CreateAnonymous<Foo>();
Run Code Online (Sandbox Code Playgroud)

但这会引发AutoFixture was unable to create an instance错误.是否可以使用自动混合自动创建结构?怎么可以这样做?请注意,我正在处理遗留代码,因此需要处理结构.:)

编辑:

IFixture fixture = new Fixture().Customize(new AutoMoqCustomization());
Run Code Online (Sandbox Code Playgroud)

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

因为它与这个问题无关.

Mar*_*ann 10

这实际上是C#编译器如何处理值类型的人工制品.虽然文档似乎另有说明,但从反射的角度来看,Foo结构没有公共构造函数.

例如,如果您执行此代码:

var ctors = typeof(Foo).GetConstructors();
Run Code Online (Sandbox Code Playgroud)

结果是一个空数组.

但是,此代码编译:

var f = new Foo();
Run Code Online (Sandbox Code Playgroud)

所以你可以说AutoFixture应该能够创建一个Foo实例.

然而,最终,可变结构是邪恶的,应该不惜一切代价避免.更好的选择是将Foo实现更改为:

public struct Foo
{
    public Foo(int bar, string baz)
    {
        this.Bar = bar;
        this.Baz = baz;
    }

    public readonly int Bar;
    public readonly string Baz;
}
Run Code Online (Sandbox Code Playgroud)

如果这样做,您现在不仅拥有(更多)正确的值类型,而且AutoFixture还能够创建实例而无需进一步修改.

因此,这是GOOS范例的一个很好的例子,您应该听取您的测试.如果它们存在摩擦,则可能是有关您的生产代码的反馈.在这种情况下,这正是你要用脚射击自己的反馈,因为价值类型的实现是有缺陷的.

PS即使你"修复"上面概述的Foo结构,有什么意义使它成为结构而不是类?它仍然包含一个字符串(引用类型)字段,因此即使结构本身将存在于堆栈中,字符串字段仍将指向堆中的数据.


我已将此问题添加为AutoFixture的可能新功能.