Domanda

I am trying to use AutoFixture to simplify my life.

How do I mock a class with

  • non-public constructor and
  • non-public Id and
  • static 'Create' method?

Example

public class User
{
    private User(){}

    /// <summary>
    ///     Created by Database...
    /// </summary>
    public long? Id { get; protected set; }

    public string Name { get; protected set; }

    public static User Create(string name)
    {
        var user = new User {Name = name};
        return user;
    }
}

I've tried using a combo of Factory and SpecimenBuilder:

    [Fact]
    public void CreatingUserWithId_Should_Work_UsingFactoryAndSpecimenBuilder()
    {
        IFixture fixture = new Fixture().Customize(new AutoFakeItEasyCustomization());
        fixture.Customizations.Add(new UserBuilder());
        fixture.Customize<User>(o => o.FromFactory(() => User.Create("foo")));

        var user = fixture.Create<User>();

        user.Should().NotBeNull();
        user.Id.Should().HaveValue();
    }

with

public class UserBuilder : ISpecimenBuilder
{
    public object Create(object request, ISpecimenContext context)
    {
        var pi = request as PropertyInfo;
        if (pi == null) return new NoSpecimen(request);

        // The following code only works for public properties... :-(
        if (pi.Name == "Id" && pi.PropertyType == typeof (long?)) return 42;

        return new NoSpecimen(request);
    }
}

A demo C# solution is available at https://github.com/draptik/MockingStaticCreate

Thankful for any pointers,

Patrick

È stato utile?

Soluzione

AF will do the right thing (User.Create() with an anonymous name arg) with no customizations whatsoever.

The only missing bit is setting the Id. Which is a question you'll have to answer for yourself -- how should your consuming code do this in the first place ? When you've decided, you could do fixture.Customize<User>( c => c.FromFactory( User.Create).Do( x => ???)

Perhaps you could consider exposing a ctor that takes an id too. Then you can do a Customize<User> ... GreedyConstructorQuery.

If your ORM is doing some wacky reflection and you like that and/or can't route around it you get to choose whether for your tests you should:

a) do that too - if that's relevant to a given test or set of tests

b) consider that to be something that just works

Regarding mixing mocking and feeding in of values to an Entity or Value object - Don't do that (Mark Seemann's Commands vs Queries article might help you here). The fact that you seem to be needing/wanting to do so makes it seems you're trying to be too ambitions in individual tests - are you finding the simplest thing to test and trying to have a single Assert testing one thing with minimal setup.

Go buy the GOOS book - it'll help you figure out ways of balancing these kinds of trade-offs.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top