2017-02-09 4 views
0

symfonyの2.8.13 /ドクトリンORM 2.5.5/5.7.5 PHPUnitのSymfony2の教義:PHPUnitの:セットエンティティID単位で嘲笑エンティティマネージャでフラッシング時には

をテストし、私はそのクラスのメソッドをテストしたいです教義エンティティマネージャを利用する。このパブリックメソッドは、Bookmarkエンティティをインスタンス化し、それをフラッシュしてこのエンティティを返すプライベートメソッドを呼び出します。その後、テストされたメソッドで、エンティティIDにアクセスする必要があります。ブックマークエンティティ自体を除いてすべてが嘲笑されます。主な問題は、自分のエンティティにsetId()メソッドがないことです。ここでコードと私の主なアイデアはこの問題を解決するが、私はそれが正しいかどうかわからないのですか?

テスト済みクラスとメソッド

class BookmarkManager 
{ 
    //... 

    public function __construct(TokenStorageInterface $tokenStorage, ObjectManager $em, Session $session) 
    { 
     //... 
    } 

    public function manage($bookmarkAction, $bookmarkId, $bookmarkEntity, $bookmarkEntityId) 
    { 
     //... 
     $bookmark = $this->add($bookmarkEntity, $bookmarkEntityId); 
     //... 
     $bookmarkId = $bookmark->getId(); 
     //... 
    } 

    private function add($entity, $entityId) 
    { 
     //... 
     $bookmark = new Bookmark(); 
     //... 
     $this->em->persist($bookmark); 
     $this->em->flush(); 

     return $bookmark; 
    } 
} 

テスト

class BookmarkManagerTest extends \PHPUnit_Framework_TestCase 
{ 
    public function testThatRestaurantAdditionToBookmarksIsWellManaged() 
    { 
     //... 
     // THIS WON'T WORK AS NO setId() METHOD EXISTS 
     $entityManagerMock->expects($this->once()) 
      ->method('persist') 
      ->will($this->returnCallback(function ($bookmark) { 
       if ($bookmark instanceof Bookmark) { 
        $bookmark->setId(1); 
       } 
      })); 
     //... 
     $bookManager = new BookmarkManager($tokenStorageMock, $entityManagerMock, $sessionMock); 
     //... 
    } 
} 

ソリューション?

1-提案hereとして反射クラスの使用を行います

$entityManagerMock->expects($this->once()) 
    ->method('persist') 
    ->will($this->returnCallback(function ($bookmark) { 
     if ($bookmark instanceof Bookmark) { 
      $class = new \ReflectionClass($bookmark); 
      $property = $class->getProperty('id'); 
      $property->setAccessible(true); 
      $property->setValue($bookmark, 1); 
      //$bookmark->setId(1); 
     } 
    })); 

2-実際の一方から延び試験Boookmarkエンティティを作成し、SETID()メソッドを追加します。次に、このクラスのモックを作成し、これを使ってReturnCallbackメソッドから取得したものを置き換えてカスタマイズしますか?それは気が狂ったようだ...

どのような考え?ご協力いただきありがとうございます。

+0

私は反射が悪いと思われることを知っていますが、あなたのリフレクション方法が最良の選択肢だと思います。 TestBookmarkやMockEntityManagerなど、テストのためだけにクラスを作成することについて何か間違っています。テストでこれを定期的に行うつもりなら、 'setProperty($ object、$ property、$ value)'メソッドが便利なReflectionSetterTraitを作成することがわかりました。 – mickadoo

+0

@mickadoo私は同意する、形質は良いオプションです。エンティティマネージャーのために、私は特定のクラスを作成しません、私はPHPUnitモックビルダーを使用してそれを擬似します。とにかく、反射はこの場合の解決策のようです。 – Cruz

答えて

1

反射は興味深いようですが、テストの可読性が低下します(モックとの混合は状況を厳しくします)。

私は、エンティティマネージャのための偽を作成して、反射に基づくIDを設定が実装されます:

class MyEntityManager implements ObjectManager 
{ 
    private $primaryIdForPersitingObject; 

    public function __construct($primaryIdForPersitingObject) 
    { 
     $this->primaryIdForPersitingObject = $primaryIdForPersitingObject; 
    } 

    ... 

    public function persist($object) 
    { 
     $reflectionClass = new ReflectionClass(get_class($object)); 
     $idProperty = $reflectionClass->getProperty('id'); 
     $idProperty->setAccessible(true); 
     $idProperty->setValue($object, $this->primaryIdForPersitingObject); 
    } 

    public function flush() { } 

    ... 
} 

あなたはこれを実装したら、あなたはMyEntityManagerのインスタンスを注入し、あなたのテストが小さく、保守が容易になります。

あなたのテストはもちろん

<?php 

class BookmarkManagerTest extends \PHPUnit_Framework_TestCase 
{ 
    public function testThatRestaurantAdditionToBookmarksIsWellManaged() 
    { 
     // ... 
     $entityManager = MyEntityManager(1); 
     //... 
     $bookManager = new BookmarkManager($tokenStorageMock, $entityManager, $sessionMock); 
     //... 
    } 
} 

ようになり

多くの永続オブジェクトに対して異なるIDを設定する必要がある場合、状況は難しいかもしれません。その後、あなたは、例えば、 persistコール別のprimaryIdForPersitingObject各エンティティクラスを持つようにさらに拡張することができる

public function persist($object) 
{ 
    $reflectionClass = new ReflectionClass(get_class($object)); 
    $idProperty = $reflectionClass->getProperty('id'); 
    $idProperty->setAccessible(true); 
    $idProperty->setValue($object, $this->primaryIdForPersitingObject); 

    $this->primaryIdForPersitingObject++; 
} 

$primaryIdForPersitingObjectを増加させることができ、そして、あなたのテストがまだきれいになります。

+0

ありがとうございます。また、反射を使用する良い方法です。ここのトリックは、異なるエンティティのIDを正しく管理することです。 Entity Managerのコンストラクタに渡されるキー/値(エンティティ/ ID)の配列がこれを単純化する可能性があります。 – Cruz

+0

@Cruzうん、それはニーズに対応するように構築する必要があります。この実装は最も簡単な概念であり、ドラフトであり、拡張するのは難しいことではありません。 –

関連する問題