2012-04-04 43 views
5

Tôi đang cố gắng xây dựng một bộ kiểm thử an toàn với Symfony2, Doctrine và MongoDB.Symfony2 Doctrine MongoDB rollback

Điều tôi cần làm là tải nhiều đồ đạc khi thử nghiệm bắt đầu và dỡ chúng khi nó kết thúc. Tôi đã nghĩ đến việc thực hiện nó với một giao dịch , nhưng ... Tôi không thể tìm thấy tài liệu về cách làm điều đó với Doctrine và Mongo!

Tôi đã tìm thấy good documentation trong tài liệu Doctrine về cách thực hiện giao dịch với ORM, nhưng không liên quan đến ODM.

Vì vậy, tôi đã xem xét các lớp source code of the Connection.php sử dụng bởi Học thuyết-Mongo quá và tôi đã không tìm thấy các beginTransaction, commitrollback phương pháp mà các dbal version sử dụng.

Tôi đã tránh khỏi thất bại, sau đó tôi tự hỏi mình "Liệu nó thậm chí có thể rollback trong MongoDB?", Và câu trả lời nếu tìm thấy trong MongoDB FAQ là:

MongoDB không sử dụng các giao dịch khóa hay phức tạp truyền thống với rollback

:(Vì vậy, tôi đoán đó là lý do tại sao không có beginTransaction hoặc bất cứ điều gì trong ODM ...

Nhưng vấn đề của tôi vẫn là: làm thế nào tôi có thể imple một loại rollback cho các bài kiểm tra của tôi?

Ý tưởng duy nhất tôi nhận được ngay bây giờ là tự lấy tất cả các id của Tài liệu tôi tải và sau đó xóa chúng trong tearDown(). Nhưng, ừm ... nó rất tệ, phải không?

Các ý tưởng khác ??

EDIT: Sau khi nhận xét đầu tiên của tôi cho câu hỏi này, liên quan đến thực tế là tôi muốn có cùng DB trong thử nghiệm và phát triển, tôi nghĩ: tại sao không sử dụng một cơ sở dữ liệu thử nghiệm riêng biệt, nơi phát triển cơ sở dữ liệu được sao chép khi các bài kiểm tra bắt đầu, và có thể được giảm nhẹ nhàng?

Có thể là ý tưởng hay hơn không? Nó thực sự trông dễ dàng hơn và an toàn hơn cho tôi. các bạn nghĩ sao?

Cảm ơn :)

+0

Tôi quên nói rằng tôi không sử dụng hai DB riêng biệt để phát triển và thử nghiệm, vì vậy một 'tearDown()' bình thường làm giảm mọi thứ không phải là giải pháp cho tôi ... – mokagio

Trả lời

4

Tôi không sử dụng hai DBS riêng biệt cho sự phát triển và thử nghiệm

Đó là điều đầu tiên cần giải quyết - bởi vì không có một db thử nghiệm, kiểm tra chạy sẽ ảnh hưởng đến db phát triển của bạn và ngược lại đó là một ý tưởng khủng khiếp. Bạn sẽ có thể chạy thử nghiệm trong môi trường sản xuất của bạn với sự tự tin tuyệt đối rằng không có gì bạn làm trong một thử nghiệm sẽ ảnh hưởng đến trang web được triển khai của bạn.

Thiết lập một kết nối thử nghiệm

Vì vậy, sửa đổi parameters.yml của bạn để có một cái gì đó như thế này:

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

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

Bên cạnh đó, trong app/config/tập tin config_test.yml bạn ghi đè mặc định connnection để bất kỳ thứ gì bạn kích hoạt như một phần của thử nghiệm yêu cầu trình quản lý tài liệu mặc định sẽ nhận được người quản lý chỉ vào db thử nghiệm của bạn:

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

Chuẩn bị cho thử nghiệm với đồ đạc

Sau đó, những gì bạn muốn làm một cách hiệu quả là:

  • cắt xén bộ sưu tập liên quan
  • đồ đạc tải

trên db thử nghiệm của bạn trước mỗi bài kiểm tra .

Dưới đây là một ví dụ trừu tượng lớp thử nghiệm:

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

Sử dụng đồ đạc trong các thử nghiệm của bạn

Với lớp thử nghiệm trừu tượng trước, sau đó bạn có thể viết các bài kiểm tra mà sử dụng dữ liệu cố định của bạn - hay không - khi thích hợp. Dưới đây là một ví dụ tầm thường.

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

Trước khi thử nghiệm, các đồ đạc bạn đã xác định sẽ được tải (cắt ngắn các bộ sưu tập mà chúng ảnh hưởng), đưa ra trạng thái db nhất quán để căn cứ vào các thử nghiệm của bạn.

+0

Cách tiếp cận này là chính xác những gì tôi đang tìm kiếm (và những gì đến trong tâm trí của tôi với chỉnh sửa cuối cùng của tôi) Tôi đồng ý với bạn thực tế là có cùng một cơ sở dữ liệu là một ý tưởng thực sự tồi. Đó là một cái gì đó "áp đặt" cho tôi, nhưng tôi đã có thể thay đổi nó cuối cùng :) – mokagio

+0

Đó là một giải pháp thực sự mát mẻ. Thật không may, điều này chỉ hoạt động của bạn không cần nhận thức container trong đồ đạc của bạn. Tải đồ đạc nhận biết container thông qua API không hoạt động, dẫn đến lỗi, đóng băng và các vấn đề khác. – Tom

+0

Nhận thức vùng chứa không ảnh hưởng đến việc sử dụng kết nối db thử nghiệm có hoạt động hay không - nếu có vẻ như bạn có một số phụ thuộc ngầm (dữ liệu) mà bạn không thỏa mãn gây ra các vòng lặp, lỗi và tình trạng lộn xộn chung. Trường hợp có thể - tập tin lịch thi đấu nên câm như đá. – AD7six

1

Chỉ cần thả cơ sở dữ liệu MongoDB của bạn trước mỗi bài kiểm tra và sau đó tải đồ đạc bạn cần. Bằng cách này, mỗi thử nghiệm sẽ được cô lập hoàn toàn.

+0

Bạn đã trả lời trong khi tôi đang chỉnh sửa và thêm tùy chọn cho câu hỏi. :) – mokagio

Các vấn đề liên quan