Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Autofixture create an anonymous type?

Suppose I'd like a call in a unit test to return an anonymous type that looks like this -

var anonymousType = { id = 45, Name="MyName", Description="Whatever" }

Could Autofixture generate anonymousType? If so, what's the syntax?

like image 354
Rich Bryant Avatar asked Apr 11 '16 15:04

Rich Bryant


2 Answers

No, AutoFixture doesn't support anonymous types, as they're internal to the library that uses them.

like image 98
Mark Seemann Avatar answered Nov 09 '22 23:11

Mark Seemann


As @MarkSeemann pointed out, AutoFixture cannot support anonymous types.

Notes on AutoFixture and dynamic

This may not apply to your specific case, but I think it's worth mentioning that if you need to create instances of dynamically typed objects in your tests – and you aren't concerned about their particular state – you can configure AutoFixture to create instances of DynamicObject that respond to any property or method that you invoke on them.

Here's an example:

public class DynamicCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customizations.Insert(
            0,
            new FilteringSpecimenBuilder(
                new FixedBuilder(new AnythingObject()),
                new ExactTypeSpecification(typeof(object))));
    }

    private class AnythingObject : DynamicObject
    {
        public override bool TryGetMember(
            GetMemberBinder binder,
            out object result)
        {
            result = new AnythingObject();
            return true;
        }

        public override bool TryInvokeMember(
            InvokeMemberBinder binder,
            object[] args,
            out object result)
        {
            result = new AnythingObject();
            return true;
        }
    }
}

In this case the AnythingObject simply returns a new instance of itself for any property or method it receives a call for. This would allow you to say for example:

var fixture = new Fixture();
fixture.Customize(new DynamicCustomization());

var foo = fixture.Create<dynamic>();

Assert.NotNull(foo.Bar);
Assert.NotNull(foo.Baz());

Another alternative – albeit more fragile – could be to use AutoFixture to create values for specific properties. In that case you would have to pass the Fixture object to AnythingObject like in this example:

public class DynamicCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customizations.Insert(
            0,
            new FilteringSpecimenBuilder(
                new FixedBuilder(new AnythingObject(fixture)),
                new ExactTypeSpecification(typeof(object))));
    }

    private class AnythingObject : DynamicObject
    {
        private readonly SpecimenContext context;

        public AnythingObject(ISpecimenBuilder builder)
        {
            context = new SpecimenContext(builder);
        }

        public override bool TryGetMember(
            GetMemberBinder binder,
            out object result)
        {
            if (binder.Name == "Bar")
            {
                result = context.Resolve(typeof(string));
            }
            else
            {
                result = new AnythingObject(context.Builder);
            }

            return true;
        }

        public override bool TryInvokeMember(
            InvokeMemberBinder binder,
            object[] args,
            out object result)
        {
            result = new AnythingObject(context.Builder);
            return true;
        }
    }
}

Here we're looking for a property named "Bar" and provide a string for it, while everything else will just get an instance of AnythingObject. So we can say:

var fixture = new Fixture();
fixture.Customize(new DynamicCustomization());

var foo = fixture.Create<dynamic>();

Assert.IsType<string>(foo.Bar);
Assert.NotNull(foo.Baz);
like image 39
Enrico Campidoglio Avatar answered Nov 10 '22 00:11

Enrico Campidoglio