Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can I replace FactoryMethodQuery for all types #1017

Closed
grzesiek-galezowski opened this issue Apr 11, 2018 · 2 comments
Closed

Can I replace FactoryMethodQuery for all types #1017

grzesiek-galezowski opened this issue Apr 11, 2018 · 2 comments
Labels

Comments

@grzesiek-galezowski
Copy link

Hi,

The current version of FactoryMethodQuery uses factory methods with fewest parameters. Unfortunately, this doesn't work for me as in many cases, I have static properties like Empty that return "null objects" and they get called which is usually not what I want.

Can I somehow configure AutoFixture to replace or remove the query?

@zvirja
Copy link
Member

zvirja commented Apr 11, 2018

Hello,

The part in the question belongs to the Engine, passed to the Fixture constructor. You can replace it if you pass the customized engine. See the full demo below (hope I correctly got your question):

public class UnitTest1
{
    [Fact]
    public void CustomizedEngineDemo()
    {
        var fixture = new Fixture(new EngineWithReplacedQuery());

        var result = fixture.Create<TypeWithNullObject>();

        Assert.NotSame(TypeWithNullObject.Empty, result);
    }

    public class EngineWithReplacedQuery : DefaultEngineParts
    {
        public override IEnumerator<ISpecimenBuilder> GetEnumerator()
        {
            using (var enumerator = base.GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    var value = enumerator.Current;

                    // Replace target method query
                    if (value is MethodInvoker mi &&
                        mi.Query is CompositeMethodQuery cmq &&
                        cmq.Queries.Skip(1).FirstOrDefault() is FactoryMethodQuery)
                    {
                        yield return new MethodInvoker(
                            new CompositeMethodQuery(
                                new ModestConstructorQuery(),
                                new PatchedFactoryMethodQuery()
                            )
                        );
                    }
                    else
                    {
                        yield return value;
                    }
                }
            }
        }
    }

    public class PatchedFactoryMethodQuery : IMethodQuery
    {
        public IEnumerable<IMethod> SelectMethods(Type type)
        {
            return from mi in type.GetTypeInfo().GetMethods(BindingFlags.Static | BindingFlags.Public)
                where mi.ReturnType == type &&
                      !string.Equals(mi.Name, "op_Implicit", StringComparison.Ordinal) &&
                      !string.Equals(mi.Name, "op_Explicit", StringComparison.Ordinal) 
                let parameters = mi.GetParameters()
                where mi.GetParameters().All(p => p.ParameterType != type)
                orderby mi.GetCustomAttribute<CompilerGeneratedAttribute>() == null ? 0 : 1, parameters.Length ascending
                select new StaticMethod(mi) as IMethod;
        }
    }


    public class TypeWithNullObject
    {
        public string Value { get; }

        private TypeWithNullObject(string value)
        {
            Value = value;
        }

        public static TypeWithNullObject Empty { get; } = new TypeWithNullObject("<empty>");

        public static TypeWithNullObject CreateValue(string value) => new TypeWithNullObject(value);
    }
}

Let me know whether it solves your issue.

P.S. I've registered a wish #1018 to simplify the default builders customization.

@grzesiek-galezowski
Copy link
Author

Thank you for your extensive help, this allowed me to solve the issue I had. Thumbs up for making this easier!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants