简体   繁体   English

使用自动混合创建结构不会引发公共构造函数错误

[英]Creating a struct with autofixture throws no public constructor error

I have a struct eg: 我有一个结构,例如:

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

and would like to create it in my unit tests using autofixture. 并希望使用自动混合在我的单元测试中创建它。 I tried using the following: 我尝试使用以下内容:

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

But this throws an AutoFixture was unable to create an instance error. 但这会引发AutoFixture was unable to create an instance错误。 Is it possible to auto create a struct with autofixture? 是否可以使用自动混合自动创建结构? How could this be done? 怎么可以这样做? Please note, that I am working on legacy code and thus need to deal with structs. 请注意,我正在处理遗留代码,因此需要处理结构。 :) :)

EDIT : 编辑:

Changed

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

To

IFixture fixture = new Fixture();

Since it wasn't relevant for the question. 因为它与这个问题无关。

This is essentially an artefact of how the C# compiler treats value types. 这实际上是C#编译器如何处理值类型的人工制品。 While the documentation seems to indicate otherwise , from the perspective of Reflection, the Foo struct has no public constructors. 虽然文档似乎另有说明 ,但从反射的角度来看,Foo结构没有公共构造函数。

Eg if you execute this code: 例如,如果您执行此代码:

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

the result is an empty array. 结果是一个空数组。

However, this code compiles: 但是,此代码编译:

var f = new Foo();

so you could argue that AutoFixture should be able to create an instance of Foo. 所以你可以说AutoFixture应该能够创建一个Foo实例。

However, in the end, mutable structs are evil and should be avoided at all cost. 然而,最终, 可变结构是邪恶的 ,应该不惜一切代价避免。 A better option is to change the Foo implementation to this: 更好的选择是将Foo实现更改为:

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

    public readonly int Bar;
    public readonly string Baz;
}

If you do this, not only do you now have a (more) correct value type, but AutoFixture is also able to create an instance without further modification. 如果这样做,您现在不仅具有(更多)正确的值类型,而且AutoFixture还能够创建实例而无需进一步修改。

Thus, this is a pretty good example of the GOOS paradigm that you should listen to your tests . 因此,这是GOOS范例的一个很好的例子,您应该听取您的测试 If they present friction, it might be feedback about your production code. 如果它们存在摩擦,则可能是有关生产代码的反馈。 In this case, this is exactly feedback that you're about to shoot yourself in the foot because the value type implementation is flawed. 在这种情况下,这正是你要用脚射击自己的反馈,因为价值类型的实现是有缺陷的。

PS Even if you 'fix' the Foo struct like outlined above, what's the point of making it a struct instead of a class? PS即使你“修复”上面概述的Foo结构,有什么意义使它成为结构而不是类? It still contains a string (reference types) field, so even though the struct itself is going to live on the stack, the string field is still going to point to data in the heap. 它仍然包含一个字符串(引用类型)字段,因此即使结构本身将存在于堆栈中,字符串字段仍将指向堆中的数据。


I've added this issue as a possible new feature for AutoFixture. 我已将此问题添加为AutoFixture的可能新功能。

Taking a cue from this blog post , I created a class that implemented the ISpecimenBuilder 从这篇博客文章中得到ISpecimenBuilder ,我创建了一个实现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;
  }
}

And added the class as customization 并将该类添加为自定义

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

causing the call to CreateAnonymous<Foo> to work. 导致对CreateAnonymous<Foo>的调用工作。

If there is a more out of the box solution, please post it and I will accept it as answer. 如果有一个更开箱即用的解决方案,请发布它,我会接受它作为答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM