2012-09-14 13 views
23

Tengo un tipo de datos con múltiples constructores y necesito AutoFixture para elegir el más codicioso (uno con la mayoría de los parámetros). El comportamiento predeterminado es elegir el constructor con el número más pequeño.Force AutoFixture para usar el constructor más codicioso

La entrada del blog del autor, http://blog.ploeh.dk/2009/03/24/HowAutoFixtureCreatesObjects.aspx, no parece implicar que exista una forma de anular este comportamiento, por lo que es posible, y si es así, ¿cómo?

Respuesta

26

This is certainly possible.

Para cambiar la estrategia para un solo tipo (MyClass):

fixture.Customize<MyClass>(c => c.FromFactory(
    new MethodInvoker(
     new GreedyConstructorQuery()))); 

Para cambiar la estrategia a través del tablero:

fixture.Customizations.Add(
    new MethodInvoker(
     new GreedyConstructorQuery())); 

Como resulta, sin embargo, utilizando GreedyConstructorQuery en general es muy problemático, como lo demuestra el siguiente fragmento de código. Imagínese una clase con este constructor:

public Foo(string name) 
{ 
    this.name = name; 
} 

Esta prueba será una excepción:

[Test] 
public void GreedyConstructor() 
{ 
    Fixture fixture = new Fixture(); 
    fixture.Customizations.Add(new MethodInvoker(new GreedyConstructorQuery())); 

    Foo foo = fixture.CreateAnonymous<Foo>(); 
} 

La excepción lanzada es:

Ploeh.AutoFixture.ObjectCreationException: AutoFixture no pudo crear una instancia de System.SByte *, muy probablemente porque no tiene un constructor público, es un tipo abstracto o no público.

¿Qué significa eso del SByte *? No hay SByte * en Foo ...

Bueno, sí, sí. Al colocar MethodInvoker en la personalización, sobrescribe todas las estrategias de creación predeterminadas, incluida la de las cadenas. En su lugar, se va a buscar el constructor más codiciosos de cadena y que es:

public String(sbyte* value, int startIndex, int length, Encoding enc); 

Y ahí está el sbyte * ...


Es todavía posible reemplazar la modesta algoritmo de selección constructor un algoritmo codicioso, es un poco más complicado de lo que me di cuenta por primera vez.

Lo que puede hacer es lo siguiente:

Escribir una pequeña clase como ésta:

public class GreedyEngineParts : DefaultEngineParts 
{ 
    public override IEnumerator<ISpecimenBuilder> GetEnumerator() 
    { 
     var iter = base.GetEnumerator(); 
     while (iter.MoveNext()) 
     { 
      if (iter.Current is MethodInvoker) 
       yield return new MethodInvoker(
        new CompositeMethodQuery(
         new GreedyConstructorQuery(), 
         new FactoryMethodQuery())); 
      else 
       yield return iter.Current; 
     } 
    } 
} 

y crear la instancia Fixture así:

Fixture fixture = new Fixture(new GreedyEngineParts()); 

que debería funcionar.

+0

Bien, me gusta que pueda especificar el comportamiento para un tipo particular.Gracias – RichK

+0

AutoFixture está realmente lanzando una ObjectCreationException cuando uso su segundo ejemplo, con el mensaje "AutoFixture no pudo crear una instancia de System.SByte * ..." Mi tipo de datos es muy simple y ciertamente no depende de un byte *! ¿Es esto un error o he usado mal el marco? – RichK

+0

Lo he intentado, y todo funciona bien con tu primer ejemplo – RichK

Cuestiones relacionadas