2012-04-04 29 views
5

Próbuję zbudować bezpieczny zestaw testów z Symfony2, Doctrine i MongoDB.Wycofanie Symfony2 DocnDB MongoDB

Co trzeba zrobić, to załadować wiele urządzeń po rozpoczęciu testu i wyładować je po zakończeniu. Myślałem o zrobieniu tego z transakcją , ale ... Nie mogłem znaleźć dokumentacji, jak to zrobić z Doctrine i Mongo!

Znalazłem good documentation w Doctrine docs dotyczące sposobu przeprowadzania transakcji z ORM, ale nie w odniesieniu do ODM.

Wziąłem więc spojrzeć na klasy source code of the Connection.php używanego przez doktryna Mongo zbyt i nie znaleźli beginTransaction, commit i rollback metody że dbal version zastosowań.

miałem bladego pojęcia, po czym spytałem się: „Czy to w ogóle możliwe, aby cofnąć się w MongoDB?”, A odpowiedź, jeśli znajdują się w MongoDB FAQ było:

MongoDB nie używa tradycyjnych blokujące lub złożone transakcje z wycofywania

:(Więc myślę, że to dlatego nie ma beginTransaction lub cokolwiek w ODM ...

Ale mój problem pozostaje: jak mogę wyko czymś w rodzaju wycofywania do moich testów?

Jedynym pomysłem jaki mam teraz jest ręczne pobranie wszystkich identyfikatorów dokumentu, który wczytałem, a następnie usunięcie ich w tearDown(). Ale, cóż ... to trochę jest do bani, prawda?

Inne pomysły?

EDIT: Po moim pierwszym komentarzu do tej kwestii, w związku z faktem, że chcę mieć taki sam DB w badania i rozwój, pomyślałem: dlaczego nie korzystają z osobnego testowej bazy danych, gdzie baza danych programistycznych zostaje skopiowana po rozpoczęciu testów i może zostać lekkomyślnie upuszczona?

Czy to może być lepszy pomysł? Wygląda na to, że jest dla mnie łatwiejszy i bezpieczniejszy. Co wy myślicie?

Dzięki :)

+0

zapomniałem powiedzieć, że nie używam dwóch oddzielnych DB dla rozwoju i testowania, więc to normalne 'łza()', że wszystko spada nie jest rozwiązaniem dla mnie ... – mokagio

Odpowiedz

4

nie używam dwa oddzielne DB dla rozwoju i testowania

to pierwszą rzeczą do rozwiązania - ponieważ bez testów db, testy uruchomione wpłynie na db rozwoju i vice versa który jest okropny pomysł. Powinieneś być w stanie uruchomić testy w środowisku produkcyjnym z całkowitą pewnością, że nic, co zrobisz w teście, nie wpłynie na twoją wdrożoną stronę.

Konfiguracja połączenia Test

więc zmodyfikować parameters.yml mieć coś takiego:

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

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

Ponadto w app/config pliku/config_test.yml przesłonić domyślne połączenie tak, aby cokolwiek wyzwalać jako część testu, który żąda domyślnego menedżera dokumentów, otrzyma menedżera wskazującego na swój test db:

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

Przygotuj się do testów z osprzętem

Następnie, czego chcą skutecznie zrobić, to:

  • obciąć odpowiednich zbiorów
  • obciążenie oprawy

na db test przed każdym testem .

Oto przykład abstract class Test:

<?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); 
    } 
} 

użytkowania lamp w badaniach

Z poprzedniej klasy abstrakcyjnej testowym, można następnie napisać testy, które wykorzystują swoje dane osprzętu - czy nie - w razie potrzeby. Poniżej jest banalny przykład.

<?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. 
    } 

Przed każdym badaniem mecze już zdefiniowane zostaną załadowane (obcinanie zbiory wpływają one), dając spójny stan db, na których można oprzeć swoje testy.

+0

Tego rodzaju podejście było dokładnie tym, czego szukałem (i co przyszło mi do głowy przy mojej ostatniej edycji). Zgadzam się z tobą, że posiadanie tej samej bazy danych jest naprawdę złym pomysłem. To było coś "narzucone" dla mnie, ale udało mi się to w końcu zmienić :) – mokagio

+0

To naprawdę fajne rozwiązanie. Niestety, to tylko działa, nie potrzebujesz świadomości pojemników w swoich urządzeniach. Ładowanie urządzeń obsługujących kontenery za pośrednictwem interfejsu API nie działa w ogóle, co prowadzi do błędów, zawieszeń i innych problemów. – Tom

+0

Świadomość kontenera nie powinna wpływać na to, czy działa testowe połączenie db - jeśli tak, to brzmi jak masz pewne niejawne zależności (dane), które nie są satysfakcjonujące powodując pętle, błędy i ogólny chaos. Gdzie to możliwe - pliki z opcjami powinny być tak głupie, jak skały. – AD7six

1

Wystarczy upuścić bazy danych MongoDB przed każdym badaniem, a następnie załadować urządzenia, które potrzebujesz. W ten sposób każdy test będzie w pełni odizolowany.

+0

Odpowiedziałeś a ja edytowanie i dodawanie tego opcja na pytanie. :) – mokagio