2015-01-12 6 views
5

私は現在大きな問題に直面しています。ユニットテストでは、テストの始めにフィクスチャを使用してデータをデータベースに追加します(すべて正常です)。テスト中にデータを追加するために、フィクスチャと同じコードを使用したいと思います。 Exemple:Symfony2、備品および単体テスト。 ManyToMany関係でテスト中にテストデータを追加

エンティティパーソン:

class Person { 
  
    /** 
     * @var integer 
     * 
     * @ORM\Column(name="id", type="integer") 
     * @ORM\Id 
     * @ORM\GeneratedValue(strategy="AUTO") 
     */ 
    private $id; 
  
    [...] 
  
    /** 
     * @ORM\ManyToMany(targetEntity="Family", cascade={"persist"}) 
     * @Assert\Count(min = "1") 
     */ 
    private $families; 
  
    public function __construct() { 
        $this->families = new \Doctrine\Common\Collections\ArrayCollection(); 
    } 
  
    public function addFamily(Family $family) { 
        $this->families[] = $family; 
        return $this; 
    } 
  
    [...] 
  
} 

エンティティ家族:

class Family { 
  
    /** 
     * @var integer 
     * 
     * @ORM\Column(name="id", type="integer") 
     * @ORM\Id 
     * @ORM\GeneratedValue(strategy="AUTO") 
     */ 
    private $id; 
  
    /** 
     * @var string 
     * @Gedmo\Slug(fields={"name"}) 
     * @ORM\Column(name="slug", type="string", length=255, unique=true) 
     */ 
    private $slug; 
  
    [...] 
  
} 

備品:

class Fixture1 implements FixtureInterface, ContainerAwareInterface { 
    /** 
     * @var Family[] 
     */ 
    public $families = array(); 
  
    public function setContainer(ContainerInterface $container = null) { 
        $this->container = $container; 
    } 
  
    public function load(ObjectManager $manager) { 
        $this->manager = $manager; 
        $SmithFamily= $this->addFamily("Smith"); 
        $this->addPerson("Will", "Smith", array($SmithFamily)); 
    } 
  
    public function addFamily($name) { 
        $family = new Family(); 
        $family->setName($name); 
        $this->manager->persist($family); 
        $this->manager->flush(); 
        $this->families[$name] = $family; 
        return $family; 
    } 
      
    public function addPerson($firstName, $lastName, array $families = array()) { 
        $person = new Person(); 
        $person->setFirstname($firstName); 
        $person->setLastname($lastName); 
        foreach ($families as $family) { 
            $person->addFamily($family); 
        } 
          
        $this->manager->persist($person); 
        $this->manager->flush(); 
        return $person; 
    } 
} 

単体テスト:

class PersonTest extends WebTestCase { 
  
    public $fixtures; 
  
    protected function setUp() { 
        $client = self::createClient(); 
        $container = $client->getKernel()->getContainer(); 
        $em = $container->get('doctrine')->getManager(); 
   
        // Purge tables 
        $purger = new \Doctrine\Common\DataFixtures\Purger\ORMPurger($em); 
        $executor = new \Doctrine\Common\DataFixtures\Executor\ORMExecutor($em, $purger); 
        $executor->purge(); 
   
        // Load fixtures 
        $loader = new \Doctrine\Common\DataFixtures\Loader; 
        $this->fixtures = new Fixture1(); 
        $this->fixtures->setContainer($container); 
        $loader->addFixture($this->fixtures); 
        $executor->execute($loader->getFixtures()); 
          
        parent::setUp(); 
    } 
  
    public function test1() { 
        $this->fixtures->addPerson("James", "Smith", array($this->fixtures->families['Smith'])); 
     [...] 
    } 
  
} 

私がテストを実行すると、私はこのエラーを取得:

教義\ DBAL \例外\ UniqueConstraintViolationException:家族。INSERT INTO」実行中 例外が発生した(スラグ、名前、 が作成した、last_updated_date、deleteddate)VALUESparams ["smith"、 "Smith"、 "2015-01-10 13:59:28"、 "2015-01-10 13:59:28"と入力した場合は(?、?、?、?、? 、NULL]:SQLSTATE [23000]:整合性制約違反: 1062 Duplicataデュチャンピオン 'スミス・ラ・音部記号を注ぐ 'UNIQ_A5E6215B989D9B62'

このエラーは、「slug」フィールドが一意でなければならないことを示します。家族がすでに存在しているにもかかわらず、新しい家族を追加しようとします。新しいPerson(James Smith)とThe Familyの間に関係を追加するだけです。なぜか分からない!

答えて

0

ここにあなたが尋ねたより少しに従いますが、私はそれは私が仕事の私の場所で十分に悪いものを見てきたようクリーナーテストを書くためにあなたを助けることを願って、私はステップバイステップでそれを見てみましょう:

まず、単体テストではありません。知っているだけです。クラスとなる小さなユニットではなく、システム全体の機能をテストしているので、機能テストと呼ばれています。

第2に、コンテナを取得するためだけに新しいクライアント(createClient呼び出し)を作成しないでください。通常、テストケースごとに複数のクライアントは必要ありません。 setUpメソッドで実際に作成したい場合は、TestCaseフィールドに格納し(TestCaseクラスの保護フィールドを作成して使用します)、setUpメソッドに格納してテストケースを使用します。これは、複数のコンテナをインスタンス化する(createClientが呼び出すたびに新しいコンテナをインスタンス化する)こと、および複数のEntitiManagersを持つことなどにより、テストスイートにバグを導入することがあるためです。そしてある時点では、あるEntityManagerに属するエンティティと別のEntityManagerに属するエンティティがあります(管理することは可能ですが、Doctrineの仕組みがわからない場合は、それを直面しない方が良いでしょう)。

第3に、あなたの例ではフィクスチャローダーは必要ありません。また、purgeは、エグゼキュータから自動的に呼び出されるため、ここで呼び出す必要はありません。これでsetUpのコードは次のようになります:

$this->client = self::createClient(); 
$em = $this->getKernel()->getContainer()->get("doctrine.orm.default_entity_manager"); 
$executor = new ORMExecutor($em, new ORMPurger()); 
$executor->execute([new Fixture1()]); 

parent::setUp(); 

私はそれがずっと簡単だと思います。

コンテナを使用する必要がない限り、実際にコンテナを使用する必要はありません。ほとんどの場合、実際にはコンテナを使用する必要はありません。

第4に、FixtureインスタンスにEntityManagerを保存しないでください。それはloadメソッドを介して取得することになっている、すべてをロードし、完全にそれを忘れるために使用します。

フィクスチャメソッドをフィールドとして使用するのではなく、引数としてマネージャを期待するように変更し、テストメソッドから(new Fixture1)->addPerson($this->client->getKernel()->getContainer()->get("doctrine.orm.default_entity_manager"), "James", "Smith", $existingFamily);を呼び出してみてください。あなたはある時点で別のマネージャーを使うように見えるので、2番目の人はまだ家族について知らないし、Personの家族のためにcascade={persist}を設定すると、それは自動的にそれを持続して再挿入しようとします。

関連する問題