2012-04-04 25 views
5

Estoy tratando de construir un conjunto de pruebas seguras con Symfony2, Doctrine y MongoDB.Symfony2 Doctrine MongoDB rollback

Lo que tengo que hacer es cargar una gran cantidad de accesorios cuando comience una prueba, y descargarlos una vez que termine. Pensé en hacerlo con una transacción , pero ... ¡No pude encontrar documentación sobre cómo hacerlo con Doctrine y Mongo!

Encontré good documentation en los documentos de Doctrine con respecto a cómo hacer transacciones con el ORM, pero no con respecto al ODM.

Así que tomó un vistazo a la clase source code of the Connection.php utilizado por Doctrina-Mongo demasiado y no he encontrado los métodos beginTransaction, commit y rollback que utiliza el dbal version.

no tenía idea, entonces me pregunté "¿Es incluso posible deshacer en MongoDB?", Y la respuesta si se encuentra en el MongoDB FAQ fue:

MongoDB no utiliza transacciones tradicionales de bloqueo o complejos con deshacer

:(Así que supongo que por eso no hay beginTransaction o en absoluto en el ODM ...

Pero mi problema sigue siendo: cómo puedo imple ¿Es una especie de retroceso para mis pruebas?

La única idea que obtuve en este momento es obtener manualmente todos los identificadores del documento que cargué y luego eliminarlos en el tearDown(). Pero, bueno ... es una mierda, ¿no?

Otras ideas ??

EDIT: Después de mi primer comentario a esta pregunta, en relación con el hecho de que yo quiero tener la misma base de datos de pruebas y desarrollo, pensé: por qué no utilizar una base de datos de prueba independiente, donde el la base de datos de desarrollo se copia cuando las pruebas comienzan, y eso se puede descartar sin problemas?

¿Podría ser una mejor idea? En realidad parece más fácil y más seguro para mí. ¿Qué piensan ustedes?

Gracias :)

+0

Olvidé decir que no estoy usando dos bases de datos separadas para el desarrollo y las pruebas, por lo que un 'tearDown()' normal que deja todo no es una solución para mí ... – mokagio

Respuesta

4

No estoy usando dos DBs separada para el desarrollo y prueba de

Eso es lo primero que debe hacer frente a - porque sin una base de datos de pruebas, las pruebas se ejecutan afectará su db desarrollo y viceversa cual es una terrible idea Debería poder ejecutar pruebas en su entorno de producción con la absoluta confianza de que nada de lo que haga en una prueba afectará su sitio desplegado.

Configuración de una conexión de prueba

Por lo tanto, modificar parameters.yml a tener algo como esto:

database.host: localhost 
database.port: 27017 
database.db: myappname 

database.test.host: localhost 
database.test.port: 27017 
database.test.db: myappname-test 

Además, en el archivo app/config/config_test.yml reemplazar el valor predeterminado conexión para que todo lo que active como parte de una prueba que solicite el administrador de documentos predeterminado reciba un administrador que señale su prueba db:

doctrine_mongodb: 
    document_managers: 
     default: 
      database: %database.test.db% 

Prepárese para las pruebas con accesorios

Entonces, lo que quiere hacer efectiva es:

  • truncar colecciones pertinentes
  • accesorios de carga

en su base de datos de prueba antes de cada prueba .

He aquí un ejemplo abstracto clase de prueba:

<?php 

use Doctrine\Common\DataFixtures\Executor\MongoDBExecutor as Executor, 
    Doctrine\Common\DataFixtures\Purger\MongoDBPurger as Purger, 
    Doctrine\Common\DataFixtures\Loader, 
    Doctrine\Common\DataFixtures\ReferenceRepository, 
    Symfony\Bundle\FrameworkBundle\Test\WebTestCase, 
    Symfony\Bundle\FrameworkBundle\Console\Application; 

abstract class AbstractTest extends WebTestCase 
{ 
    /** 
    * Array of fixtures to load. 
    */ 
    protected $fixtures = array(); 

    /** 
    * Setup test environment 
    */ 
    public function setUp() 
    { 
     $kernel = static::createKernel(array('environment' => 'test', 'debug' => false)); 
     $kernel->boot(); 
     $this->container = $kernel->getContainer(); 
     $this->dm = $this->container->get('doctrine.odm.mongodb.document_manager'); 

     if ($this->fixtures) { 
      $this->loadFixtures($this->fixtures, false); 
     } 
    } 

    /** 
    * Load fixtures 
    * 
    * @param array $fixtures names of _fixtures to load 
    * @param boolean $append append data, or replace? 
    */ 
    protected function loadFixtures($fixtures = array(), $append = true) 
    { 
     $defaultFixtures = false; 

     $loader = new Loader(); 
     $refRepo = new ReferenceRepository($this->dm); 

     foreach ((array) $fixtures as $name) { 
      $fixture = new $name(); 
      $fixture->setReferenceRepository($refRepo); 
      $loader->addFixture($fixture); 
     } 

     $purger = new Purger(); 
     $executor = new Executor($this->dm, $purger); 
     $executor->execute($loader->getFixtures(), $append); 
    } 
} 

Usar instalaciones en sus pruebas de

Con la clase de pruebas genéricas anterior, a continuación, puede escribir pruebas que utilizan sus datos accesorio - o no - según sea apropiado. A continuación hay un ejemplo trivial.

<?php 

use Your\AbstractTest, 
    Your\Document\Foo; 

class RandomTest extends AbstractTest 
{ 
    /** 
    * fixtures to load before each test 
    */ 
    protected $fixtures = array(
     'APP\FooBundle\DataFixtures\MongoDB\TestFoos', 
     'APP\FooBundle\DataFixtures\MongoDB\TestBars' 
    ); 

    ... 

    /** 
    * Check it gets an ID (insert succeeded) 
    * 
    */ 
    public function testCreateDefaults() 
    { 
     $foo = new Foo(); 
     $this->dm->persist($foo); 
     $this->dm->flush(); 

     $this->assertNotNull($foo->getId()); 
     $this->assertSame('default value', $foo->getSomeProperty()); 
     // etc. 
    } 

    /** 
    * Check result of something with a given input 
    * 
    */ 
    public function testSomething() 
    { 
     $foo = $this->dm->getRepository(APPFooBundle:Foo)->findByName('Some fixture object'); 

     $foo->doSomething(); 
     $this->assertSame('modified value', $foo->getSomeProperty()); 
     // etc. 
    } 

Antes de cada prueba, los accesorios que ha definido se cargarán (truncando las colecciones que afectan), dando un estado db consistentes en la que basar sus pruebas.

+0

Este tipo de enfoque es exactamente lo que estaba buscando (y lo que me vino a la mente con mi última edición) Estoy de acuerdo con el hecho de que tener la misma base de datos es una muy mala idea. Eso fue algo "impuesto" para mí, pero pude cambiarlo por fin :) – mokagio

+0

Esa es una solución genial. Desafortunadamente, esto solo funciona de usted, no necesita conocimiento del contenedor en sus accesorios. La carga de dispositivos compatibles con contenedores a través de la API no funciona en absoluto, lo que genera errores, bloqueos y otros problemas. – Tom

+0

El conocimiento del contenedor no debe afectar si funciona el uso de una conexión db de prueba; si lo hace, parece que tienes dependencias implícitas (de datos) que no estás satisfaciendo y que causan bucles, errores y caos general. Donde sea posible, los archivos de instalación deberían ser tan tontos como las rocas. – AD7six

1

tan sólo reduce su base de datos MongoDB antes de cada prueba y luego se cargan los accesorios que necesita. De esta forma, cada prueba estará completamente aislada.

+0

Respondió mientras editaba y agregó esto opción a la pregunta. :) – mokagio

Cuestiones relacionadas