2016-12-03 101 views
3

對不起我的問題很長。如何用Symfony在serviceTest中模擬EntityManager?

如何嘲笑的EntityManager延長KernelTestCase服務測試?現在

,解釋和我的測試...

我使用Symfony3.2。我的應用是標準的。我有一些控制器,我使用WebTestCase來測試它們。

Generaly,我控制器驗證參數,調用服務/管理人員,處理一些變量,並推動他們查看和我的測試是非常簡單的延長WebTestCase測試。

/** 
* Test New Game Action 
*/ 
public function testFooAction(){ 
    //We mock the Service 
    $fooService = $this 
     ->getMockBuilder(GameService::class) 
     ->disableOriginalConstructor() 
     ->getMock(); 
    $fooService->expects(self::once()) 
     ->method('barMethod') 
     ->willReturn($result); 

    //We create the client 
    $client = static::createClient(); 
    $container = $client->getContainer(); 

    //I put my mock here 
    $container->set('app.game-service', $fooService); 

    //I launch the request 
    $client->request('GET', '/foo'); 
    //I handle the response 
    $response = $client->getResponse(); 

    //I do some tests like this one 
    self::assertEquals(200, $response->getStatusCode()); 

} 

正如你所看到的,我不叫EntityManger,因爲我用服務這些線路把我的服務的模擬

//We create the client 
    $client = static::createClient(); 
    $container = $client->getContainer(); 

    //I put my mock here 
    $container->set('app.game-service', $fooService); 

我嘲笑實體管理中存在的問題我的服務。我的控制器已通過測試,但未通過我的服

這裏的構造函數初始化一個簡單的保護財產的EntityManager。問題是這樣的保護你會看的更遠......

/** 
    * FooService constructor. 
    * @param EntityManager $entityManager 
    */ 
    public function __construct(EntityManager $entityManager) 
    { 
      $this->entityManager = $entityManager; 
    } 

測試我的服務,這是我最初的代碼:

<?php 
class FooServiceTest extends KernelTestCase 
{ 
    /** 
    * Foo Service. 
    * 
    * @var FooService 
    */ 
    private $fooService; 

    /** 
    * Prepares the environment before running each test. 
    */ 
    protected function setUp() 
    { 
     parent::setUp(); 

     self::bootKernel(); 
     $this->fooService = static::$kernel->getContainer() 
      ->get('app.foo-service') //HERE IS HOW I HANDLE MY SERVICE TO TEST IT 
     ; 

    } 

testStart完美的作品,有一定的數據庫交互。

我知道我可以測試期間回滾數據。但我想嘲弄的EntityManager 驗證commit方法的召喚。

我試試這個來模擬實體管理器在我的設置:

protected function setUp() 
    { 
     parent::setUp(); 

     $entityManager = $this 
      ->getMockBuilder('Doctrine\ORM\EntityManager') 
      ->disableOriginalConstructor() 
      ->getMock(); 
     $entityManager 
      ->expects(once()) // I WANT EXACTLY ONE CALL TO COMMIT METHOD 
      ->method('commit') 
      ->willReturn(null); 

     self::bootKernel(); 
     $container = static::$kernel->getContainer(); 
     $container->set('doctrine.orm.entity_manager', $entityManager); // THIS LINE DOES NOTHING <======= 
     $this->gameService = static::$kernel->getContainer() 
      ->get('app.game-service') 
     ; 

帖碼不起作用。模擬不到位。我仍然擁有真正的entityManager。我認爲這是因爲集裝箱已經關閉了。做到這一點是螺母有用設置

就像一個野蠻人,我EntityManager的屬性更改爲公共

而且我這樣做:

protected function setUp() 
    { 
     parent::setUp(); 

     $entityManagerMock = $this 
      ->getMockBuilder('Doctrine\ORM\EntityManager') 
      ->disableOriginalConstructor() 
      ->getMock(); 
     $entityManagerMock 
      ->expects(once()) // I WANT EXACTLY ONE CALL TO commit METHOD 
      ->method('commit') 
      ->willReturn(null); 

     self::bootKernel(); 
     $this->gameService = static::$kernel->getContainer() 
      ->get('app.game-service') 
     ; 
     $this->gameService->entityManager = entityManagerMock; 

它完美。測試可以運行。但是,這不是一個很好的做法,在公共財產一個EntityManager

我的問題是:如何嘲笑的EntityManager在服務測試?

(對不起,我的英語不流利)

+1

我認爲你應該選擇你的測試是一個單元測試(你會模擬你的依賴或WebTestCase,在這種情況下,你應該使用測試數據庫並且像平常一樣使用你的應用程序而不嘲笑。我也喜歡「像野蠻人一樣,我將entityManager屬性更改爲公開」 – mickadoo

回答

1

首先在你的代碼的

$container->set('doctrine.orm.entity_manager'); // THIS LINE DOES NOTHING <======= 

我敢肯定,你錯過了第二個參數:)

另注:唐嘲笑你不擁有的東西。 將來您將運行composer update,EntityManager的commit將會有一些可選的isReallyCommit參數。你的代碼將被破壞,但你不會注意到它,因爲測試是綠色的。我知道這不太可能,但無論如何,這只是一個例子。我覺得這裏的好的做法是

  • 有一些適配器與實體管理器incapsulated
  • 模擬中的服務單位,適配器測試
  • 測試與對真實的數據庫功能測試適配器沒有嘲笑任何

或只是不要單位測試您的服務,但使功能與真正的數據庫交互測試

+0

感謝您的幫助!我不確定要理解這句話的含義:使用包含實體管理器的適配器。你能編輯你的答案給我一個簡單的例子嗎? –