Pregunta

Estoy tratando de utilizar SUT fábrica 'patrón' para crear mi SUT.

Dada la estructura SUT:

namespace MySut
{
    public class Dep1
    {
    }

    public class Dep2
    {
    }

    public class Sut
    {
        public Sut( Dep1 dep1, Dep2 dep2 )
        {
        }
    }
}

Estoy usando AutoFixture , y me pregunto ¿cuál es la mejor manera de colapsar las siguientes especificaciones y el SUT asociado método de fábrica [valiosa pero] busywork:

namespace MySpecifications
{
    using MySut;
    public class MySpecification
    {
        public void TestCore()
        {
            // Dont care about dependencies, testing core functionality
            var sut = CreateSut();
        }

        public void TestDep1Interaction()
        {
            // Dont care about Dep2, want to observe stuff on the Dep1 dependent object
            var sut = CreateSut( new Mock<Dep1>().Object );
        }

        public void TestDep2Interaction()
        {
            // Dont care about Dep1, want to observe stuff on the Dep2 dependent object
            var sut = CreateSut( new Mock<Dep2>().Object );
        }

        private object CreateSut( )
        {
            return CreateSut( CreateDep1(), CreateDep2() );
        }

        private object CreateSut( Dep1 dep1 )
        {
            return CreateSut( dep1, CreateDep2() );
        }

        private object CreateSut( Dep2 dep2 )
        {
            return CreateSut( CreateDep1(), dep2 );
        }

        private Sut CreateSut( Dep1 dep1, Dep2 dep2 )
        {
            return new Sut( dep1, dep2 );
        }

        private static Dep1 CreateDep1()
        {
            return new Fixture().CreateAnonymous<Dep1>();
        }

        private static Dep2 CreateDep2()
        {
            return new Fixture().CreateAnonymous<Dep2>();
        }
    }
}

a algo como:

    public class MyAutoFixturedSpecification
    {
        public void TestCore()
        {
            // Dont care about dependencies, testing core functionality
            var sut = CreateSut();
        }

        public void TestDep1Interaction()
        {
            // Dont care about Dep2, want to observe stuff on the Dep1 dependent object
            var sut = CreateSut( new Mock<Dep1>().Object );
        }

        public void TestDep2Interaction()
        {
            // Dont care about Dep1, want to observe stuff on the Dep2 dependent object
            var sut = CreateSut( new Mock<Dep2>().Object );
        }

        private object CreateSut( params object[] injectedNonAnonymouses )
        {
            return new Fixture(  ).Build<Sut>(  )./*??????*/;
        }
    }

o

    public class MyAnticipatedAutoFixturedSpecification
    {
        public void TestCore()
        {
            // Dont care about dependencies, testing core functionality
            var sut = new Fixture(  ).Build<Sut>().CreateAnonymous(  );
        }

        public void TestDep1Interaction()
        {
            // Dont care about Dep2, want to observe stuff on the Dep1 dependent object
            var sut = new Fixture().Build<Sut>()/*.With( new Mock<Dep1>().Object )*/.CreateAnonymous();
        }

        public void TestDep2Interaction()
        {
            // Dont care about Dep1, want to observe stuff on the Dep2 dependent object
            var sut = new Fixture().Build<Sut>()/*.With( new Mock<Dep2>().Object )*/.CreateAnonymous();
        }
    }
.

es decir, la eliminación de toda la basura de la fábrica, por lo que mis especificaciones pueden fácilmente hacer frente a una transición a:

namespace MySutWithNewDependency
{
    public class Dep1
    {
    }

    public class Dep2
    {
    }

    public class Dep3
    {
    }

    public class Sut
    {
        public Sut( Dep1 dep1, Dep2 dep2, Dep3 dep3 )
        {
        }
    }
}

Si bien hay una superposición con la noción de un contenedor automocking, todavía no estoy buscando un martillo de oro - sólo una manera de ser capaz de burlarse de 0 o 1 cosa a la vez y sin embargo ser capaz de personalizar la creación de dependientes objetos sin tener que volver a las llamadas explícitas al constructor Sut siempre que su conjunto de dependencias cambios.

(también usando xUnit.net (estilo SubSpec), Moq, Ninject2 (aunque no desea utilizar DI en mis especificaciones))

¿Fue útil?

Solución

AutoFixture puede más o menos hacer todo esto para usted sin todo ese andamiaje adicional. Yo empezaría con un accesorio básico y lo uso para Sut resolución:

var fixture = new Fixture();
var sut = fixture.CreateAnonymous<Sut>();

Esto supone que Dep1 y Dep2 puede ser creado automáticamente por AutoFixture, pero tal como se presentan, pueden porque tienen constructores por defecto.

Cuando se desea anular un tipo específico, puede utilizar el método de registro de la siguiente manera:

var fixture = new Fixture();

var mock = new Mock<Dep1>();
fixture.Register(mock.Object);
// Setup mock if necessary...

var sut = fixture.CreateAnonymous<Sut>();

Esto hará que fixture al uso mock.Object es necesaria ninguna Dep1 momento, incluso cuando se invoca el constructor Sut. Esto sin duda se adapte a su condición de ser robusta frente a la evolución de los constructores, y una de las principales razones AutoFixture fue construido por el estilo.

En un escenario más realista, DEP1 y DEP2 podrían ser interfaces, en cuyo caso es posible que desee registrar como parte de un 'defecto Fixture'. Este es, sin duda también, posiblemente debido a que última llamada al Registro gana . Esto significa que se puede configurar una instancia del accesorio con unos buenos valores por defecto y aún así ser capaz de anular tipos específicos siempre que lo necesite para hacer esto.

Yo personalmente uso AutoFixture como un contenedor de auto-burla. Esta discusión proporciona un indicio de lo que sería posible con la AutoFixture 1.1 API, pero el nuevo núcleo para AutoFixture 2.0 proporcionarán mucho mejores opciones de extensibilidad. Cuando llego a ella, voy a escribir un post sobre este tema.

P.S. Lo siento por la respuesta tardía, pero no vi tu pregunta antes de ahora. En el futuro, no dude en hacer ping (por ejemplo, en Twitter) para una rápida respuesta.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top