Autofixture: Congelar un simulacro no anula una instancia inyectada

Creado en 31 jul. 2018  ·  1Comentario  ·  Fuente: AutoFixture/AutoFixture

Comportamiento actual

Al inyectar dos instancias concretas, la segunda instancia anula la primera.

Al inyectar una instancia concreta, seguida de una instancia simulada, la segunda instancia no anula la primera.

Esto hace que la idea de realizar algunas pruebas que usen un simulacro y algunas pruebas que usen una implementación (usando un constructor de clases de prueba para compartir un accesorio entre las pruebas) sea bastante incómoda.

Comportamiento esperado

Al inyectar dos instancias concretas, la segunda instancia anula la primera.

Al inyectar una instancia concreta, seguida de una instancia simulada, la segunda instancia anula la primera.

Ejemplo de comportamiento esperado

`` C #
usando System.Collections.Generic;
usando AutoFixture;
usando AutoFixture.AutoMoq;
usando Moq;
usando Xunit;

espacio de nombres SomeNamespace
{
AutoFixtureTests de clase pública
{
[Hecho]
// Pases
public void Should_OverridePreviouslyInjectedString ()
{
const string test1 = "test1";
const string test2 = "test2";

        var fixture = new Fixture();

        fixture.Inject(test1);
        fixture.Inject(test2);

        Assert.Equal(fixture.Create<string>(), test2);
    }

    [Fact]
    // Fails
    public void Should_OverridePreviouslyInjectedInstance()
    {
        var fixture = new Fixture().Customize(new AutoMoqCustomization());

        var sut1 = new List<int>();

        fixture.Inject<IList<int>>(sut1);
        fixture.Freeze<Mock<IList<int>>>();

        var sut2 = fixture.Create<IList<int>>();

        Assert.NotSame(sut1, sut2);
    }
}

}
''

question

Comentario más útil

Hola @ charles-salmon,

Gracias por tomarse el tiempo para informar esto.

El comportamiento que está observando es _por diseño_. Permíteme explicarte. 🙂

Si observa la implementación del método Freeze<T> :

var value = fixture.Create<T>();
fixture.Inject(value);
return value;

Verá que todo lo que está haciendo es crear una muestra de T e inyectarla en el dispositivo. De hecho, el método Freeze surgió como un atajo útil para esta misma operación. Como escribió @ploeh en su publicación en la que presentó el método Freeze en 2010:

Resultó que usamos tanto este idioma de codificación que decidimos encapsularlo en un método de conveniencia. Después de un poco de debate, llegamos al nombre Freeze, porque básicamente congelamos una sola variable anónima en el dispositivo, omitiendo el algoritmo predeterminado para crear nuevas instancias.

Dado eso, no debería sorprender que congelar el mismo tipo T como una instancia inyectada produzca la misma instancia.

Ahora, para abordar su punto:

Esto hace que la idea de realizar algunas pruebas que usen un simulacro y algunas pruebas que usen una implementación (usando un constructor de clases de prueba para compartir un accesorio entre las pruebas) sea bastante incómoda.

Dado que un dispositivo representa el _contexto_ en el que se ejecuta una prueba, ciertamente _ puede_ tener varias pruebas que compartan el mismo dispositivo ; sin embargo, esto tiene el costo de mezclar múltiples preocupaciones, y posiblemente conflictivas.

El libro xUnit Patterns lo resume muy bien :

El mayor problema con un dispositivo compartido es que puede provocar "colisiones" entre las pruebas, lo que posiblemente resulte en pruebas erráticas , ya que las pruebas pueden depender de los resultados de otras pruebas. Otro problema es que un accesorio diseñado para servir muchas pruebas seguramente será mucho más complicado que el accesorio mínimo necesario para una sola prueba.

Esta "colisión" es exactamente lo que sucede cuando una prueba espera que un objeto de tipo T sea ​​una instancia específica, mientras que otra prueba espera que T sea ​​un objeto falso .

Como no puedo pensar en un escenario de prueba en el que tenga sentido que el mismo tipo T sea ​​un simulacro _y_ una instancia concreta (aunque estoy feliz de que se demuestre que estoy equivocado), sugiero que tenga estos Las pruebas utilizan diferentes accesorios, cada uno configurado para servir a su escenario particular.

>Todos los comentarios

Hola @ charles-salmon,

Gracias por tomarse el tiempo para informar esto.

El comportamiento que está observando es _por diseño_. Permíteme explicarte. 🙂

Si observa la implementación del método Freeze<T> :

var value = fixture.Create<T>();
fixture.Inject(value);
return value;

Verá que todo lo que está haciendo es crear una muestra de T e inyectarla en el dispositivo. De hecho, el método Freeze surgió como un atajo útil para esta misma operación. Como escribió @ploeh en su publicación en la que presentó el método Freeze en 2010:

Resultó que usamos tanto este idioma de codificación que decidimos encapsularlo en un método de conveniencia. Después de un poco de debate, llegamos al nombre Freeze, porque básicamente congelamos una sola variable anónima en el dispositivo, omitiendo el algoritmo predeterminado para crear nuevas instancias.

Dado eso, no debería sorprender que congelar el mismo tipo T como una instancia inyectada produzca la misma instancia.

Ahora, para abordar su punto:

Esto hace que la idea de realizar algunas pruebas que usen un simulacro y algunas pruebas que usen una implementación (usando un constructor de clases de prueba para compartir un accesorio entre las pruebas) sea bastante incómoda.

Dado que un dispositivo representa el _contexto_ en el que se ejecuta una prueba, ciertamente _ puede_ tener varias pruebas que compartan el mismo dispositivo ; sin embargo, esto tiene el costo de mezclar múltiples preocupaciones, y posiblemente conflictivas.

El libro xUnit Patterns lo resume muy bien :

El mayor problema con un dispositivo compartido es que puede provocar "colisiones" entre las pruebas, lo que posiblemente resulte en pruebas erráticas , ya que las pruebas pueden depender de los resultados de otras pruebas. Otro problema es que un accesorio diseñado para servir muchas pruebas seguramente será mucho más complicado que el accesorio mínimo necesario para una sola prueba.

Esta "colisión" es exactamente lo que sucede cuando una prueba espera que un objeto de tipo T sea ​​una instancia específica, mientras que otra prueba espera que T sea ​​un objeto falso .

Como no puedo pensar en un escenario de prueba en el que tenga sentido que el mismo tipo T sea ​​un simulacro _y_ una instancia concreta (aunque estoy feliz de que se demuestre que estoy equivocado), sugiero que tenga estos Las pruebas utilizan diferentes accesorios, cada uno configurado para servir a su escenario particular.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

Eldar1205 picture Eldar1205  ·  5Comentarios

malylemire1 picture malylemire1  ·  7Comentarios

mjfreelancing picture mjfreelancing  ·  4Comentarios

ecampidoglio picture ecampidoglio  ·  7Comentarios

Ephasme picture Ephasme  ·  3Comentarios