2012-10-17 71 views
6

我有一个结构例如为:创建具有autofixture一个struct抛出没有公共构造错误

public struct Foo 
{ 
    public int Bar; 
    public string Baz; 
} 

,并想在使用autofixture我的单元测试来创建它。我尝试使用以下内容:

IFixture fixture = new Fixture(); 
var f = fixture.CreateAnonymous<Foo>(); 

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

编辑:

改变

IFixture fixture = new Fixture().Customize(new AutoMoqCustomization()); 

IFixture fixture = new Fixture(); 

由于这是不相关的问题。

+0

如果您取消AutoMoq自定义,它是否有所不同? –

+0

它没有任何区别。 – Rok

+1

酷 - 无法解决问题,@Peter Porfy可以消除他的猜测... –

回答

8

这本质上是C#编译器如何处理值类型的一种人造物。虽然the documentation seems to indicate otherwise,从反射的角度来看,Foo结构没有公共构造函数。

E.g.如果您执行此代码:

var ctors = typeof(Foo).GetConstructors(); 

结果是一个空数组。

然而,这个代码编译:

var f = new Foo(); 

,所以你可能会说,AutoFixture应该能够创建富的一个实例。

然而,最终,mutable structs are evil,应该不惜一切代价避免。更好的选择是改变美孚实现这样:

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

    public readonly int Bar; 
    public readonly string Baz; 
} 

如果你这样做,你不仅现在有一个(更)正确的值类型,但AutoFixture也能没有进一步修改,以创建一个实例。

因此,这是GOOS范例的一个很好的例子,您应该倾听您的测试。如果它们存在摩擦,它可能是关于您的生产代码的反馈。在这种情况下,这正是反馈意见,因为值类型实现是有缺陷的,所以您即将在脚中自拍。

P.S.即使你像上面概述的那样'修复'Foo结构,将它变成一个结构而不是一个类又有什么意义呢?它仍然包含一个字符串(引用类型)字段,所以即使结构本身要在栈中生存,字符串字段仍然会指向堆中的数据。


我已经添加了this issue作为AutoFixture的一个可能的新功能。

+0

谢谢您的详尽答案!我将添加构造函数结构,因为这不会影响遗留代码,但由于相同的原因,我不能使它们不可变。 至于结构,它们被用作DTO的遗留代码。因为在我看来,类更适合工作,所以我试图重构一部分代码来使用类。但是由于结构仍然会被代码的其他部分使用,所以我需要测试它们和替换类之间的转换。我希望我用这个用例。 :)也请回复,如果功能得到实施! – Rok

1

从这个blog post得到暗示,我创建了一个实现的ISpecimenBuilder

class FooBuilder : ISpecimenBuilder 
{ 
    public object Create(object request, ISpecimenContext context) 
    { 
    var sr = request as SeededRequest; 
    if (sr == null) 
    { 
     return new NoSpecimen(request); 
    } 
    if (sr.Request != typeof(Foo)) 
    { 
     return new NoSpecimen(request); 
    } 

    var foo = new Foo(); 
    foo.Bar = context.CreateAnonymous<int>(); 
    foo.Baz = context.CreateAnonymous<string>(); 
    return foo; 
    } 
} 

,并添加了类作为定制

fixture.Customizations.Add(new FooBuilder()); 

导致调用CreateAnonymous<Foo>工作一类。

如果有更多开箱即用的解决方案,请发布,我会接受它作为答案。

+0

+1你可能能够使用'AutoPropertiesCommand如[本讨论](http://autofixture.codeplex.com/discussions/222358)所示,以自动完成任务 - –

+0

@anonympous Downvoter。任何你愿意分享的理由?在没有更好的解决方案的情况下,这是一个工作(我敢说它是最常用的方式,因为它以正确的方式挂住了管道)解决方法(尤其是其他的泛化) –

相关问题