10

I have a struct e.g.:

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. 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.

Rok
  • 705
  • 8
  • 20
  • If you take out the AutoMoq customization, does it make a differnce or not? – Ruben Bartelink Oct 17 '12 at 11:58
  • It doesn't make any difference. – Rok Oct 17 '12 at 12:30
  • 1
    Cool - take it out of the question and @Peter Porfy can remove his speculation... – Ruben Bartelink Oct 17 '12 at 16:23
  • 1
    Normally, you don't need the `AutoMoqCustomization`. (There is no abstract class or interface inside the `Foo` type that could be auto-mocked using Moq.) – Nikos Baxevanis Oct 17 '12 at 19:45
  • @RubenBartelink which part is wrong with my speculation Mr. Ruben? – Peter Porfy Oct 17 '12 at 20:36
  • 2
    @PeterPorfy the mocking (/mock proxy) bit - AF Core is just loads of reflection with very few dependencies. The `AutoFixture.AutoMoq` extension in which `AutoMoqCustomization` lives is the only thing that could possibly bring it into play. (Not saying it was a bad guess or unreasonable - it's just *if the AMC is taken out* it would be going out on a limb to suggest that dynamic proxies are in play) – Ruben Bartelink Oct 17 '12 at 20:52
  • @RubenBartelink thanks for clarifying this, I deleted my answer – Peter Porfy Oct 18 '12 at 08:10
  • @PeterPorfy I personally wouldn't delete your answer - it's an important consideration. I'd just add an EDIT saying that the clarification from the OP (If that ever gets edited in *nudge nudge*) turned out to rule it out. (OTOH if you want, say the word and I'll delete this and the preceding two comments – Ruben Bartelink Oct 18 '12 at 09:36
  • Nudge received. :D I am still new to this posting thing, so thanks for pointers. – Rok Oct 18 '12 at 10:48

2 Answers2

11

This is essentially an artefact of how the C# compiler treats value types. While the documentation seems to indicate otherwise, from the perspective of Reflection, the Foo struct has no public constructors.

E.g. 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.

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:

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.

Thus, this is a pretty good example of the GOOS paradigm that you should listen to your tests. 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.

P.S. Even if you 'fix' the Foo struct like outlined above, what's the point of making it a struct instead of a class? 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.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • Thank you for the exhaustive answer! I will add constructors to structs, since this will not affect the legacy code, but because of the same reason I can't make them immutable. As for the structs, they are used as DTO's by the legacy code. Since in my opinion classes are more suitable for the job, I'm trying to refactor a part of the code to use classes instead. But since structs will still be used by other parts of the code, I need to test conversions between them and replacement classes. I hope I make a use case with this. :) Also please post back, if feature get's implemented! – Rok Oct 18 '12 at 07:35
1

Taking a cue from this blog post, I created a class that implemented the 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.

If there is a more out of the box solution, please post it and I will accept it as answer.

Rok
  • 705
  • 8
  • 20
  • +1 You might be able to use `AutoPropertiesCommand` as shown in [this discussion](http://autofixture.codeplex.com/discussions/222358) to automate the assignment - – Ruben Bartelink Oct 17 '12 at 16:28
  • @anonympous Downvoter. Any reasons you'd care to share? In the absence of a better solution, this is a working (and dare I say it al#most idiomatic in terms of the fact that it hooks the pipeline in the correct manner) workaround (esp with the other generalization) – Ruben Bartelink Oct 17 '12 at 20:54