2015-04-10 4 views
0

Я работаю над приложением для клиента, но у меня проблемы с тестированием репозиториев.Laravel 4 - Тестирование шаблонов репозитория с помощью PHPUnit и mockery

Чтобы связать репозиторий модели у меня есть следующий код:

<?php 

namespace FD\Repo; 

use App; 
use Config; 

/** 
* Service Provider for Repository 
*/ 
class RepoServiceProvider extends \Illuminate\Support\ServiceProvider 
{ 
    public function register() 
    { 
     $app = $this->app; 

     $app->bind('FD\Repo\FactureSst\FactureSstInterface', function ($app) { 
      return new FactureSst\EloquentFactureSst(App::make('FactureSst'), new \FD\Service\Cache\LaravelCache($app['cache'], 'factures_sst', 10)); 
     }); 
    } 
} 

Репозиторий затем расширяет абстрактный класс, содержащие функции из красноречивого ОРМА (найти, где все и т.д.). Код хранилища выглядит примерно так:

<?php 

namespace FD\Repo\FactureSst; 

use Illuminate\Database\Eloquent\Model; 
use FD\Repo\AbstractBaseRepo; 
use FD\Repo\BaseRepositoryInterface; 
use FD\Service\Cache\CacheInterface; 
use Illuminate\Support\Collection; 

class EloquentFactureSst extends AbstractBaseRepo implements BaseRepositoryInterface, FactureSstInterface 
{ 
    protected $model; 
    protected $cache; 

    public function __construct(Model $resource, CacheInterface $cache) 
    { 
     $this->model = $resource; 
     $this->cache = $cache; 
    } 

    /** 
    * Retrieve factures with the given SST and BDC IDs. 
    * 
    * @param int $sst_id 
    * @param int $bdc_id 
    * @return \Illuminate\Support\Collection 
    */ 
    public function findWithSstAndBdc($sst_id, $bdc_id) 
    { 
     $return = new Collection; 

     $factures = $this->model->where('id_sst', $sst_id) 
      ->whereHas('facture_assoc', function ($query) use ($bdc_id) { 
       $query->where('id_bdc', $bdc_id); 
      }) 
      ->get(); 

     $factures->each(function ($facture) use (&$return) { 
      $data = [ 
       'facture_id' => $facture->id, 
       'facture_name' => $facture->num_facture, 
       'total_dsp' => $facture->total_dsp(), 
       'total_tradi' => $facture->total_tradi() 
      ]; 

      $return->push($data); 
     }); 

     return $return; 
    } 
} 

Для проверки запросов к базе я использую издевательство, как звонки в базу данных будут слишком долго. Вот мой тестовый класс:

<?php namespace App\Tests\Unit\Api\FactureSst; 

use App; 
use FactureSst; 
use Illuminate\Database\Eloquent\Collection; 
use Mockery as m; 
use App\Tests\FdTestCase; 

class FactureSstTest extends FdTestCase 
{ 
    /** 
    * The primary repository to test. 
    */ 
    protected $repo; 

    /** 
    * Mocked version of the primary repo. 
    */ 
    protected $mock; 

    public function setUp() 
    { 
     parent::setUp(); 
     $this->repo = App::make('FD\Repo\FactureSst\FactureSstInterface'); 
     $this->mock = $this->mock('FD\Repo\FactureSst\FactureSstInterface'); 
    } 

    public function tearDown() 
    { 
     parent::tearDown(); 
     m::close(); 
    } 

    public function mock($class) 
    { 
     $mock = m::mock($class); 
     $this->app->instance($class, $mock); 
     return $mock; 
    } 

    public function testFindingBySstAndBdc() 
    { 
     $this->mock->shouldReceive('where')->with('id_sst', 10)->once()->andReturn($this->mock); 
     $this->mock->shouldReceive('whereHas')->with('facture_assoc')->once()->andReturn($this->mock); 
     $this->mock->shouldReceive('get'); 

     $result = $this->repo->findWithSstAndBdc(30207, 10); 
     $this->assertEquals($result, new \Illuminate\Support\Collection); 
     $this->assertEquals($result->count(), 0); 
    } 
} 

Как вы можете видеть в тесте, я просто пытаюсь вызвать функцию и убедитесь, что функции прикованы правильно. Однако я продолжаю получать сообщение об ошибке:

App\Tests\Unit\Api\FactureSst\FactureSstTest::testFindingBySstAndBdc Mockery\Exception\InvalidCountException: Method where("id_sst", 10) from Mockery_0_FD_Repo_FactureSst_FactureSstInterface should be called exactly 1 times but called 0 times.

Пожалуйста, помогите мне понять, почему это не работает и как его исправить. Извините, что код на французском языке, приложение для французского клиента.

Заранее спасибо.

ответ

1

Похоже, что вы издеваетесь над репозиторием, когда вы действительно должны издеваться над зависимостями этого репозитория, а именно Illuminate\Database\Eloquent\Model, в котором вы собираетесь попасть в базу данных.

Измените setUp() так, чтобы он создавал макет объекта Illuminate\Database\Eloquent\Model, а затем он должен вводить этот макет объекта при создании экземпляра вашего репозитория.

public function setUp() 
{ 
    parent::setUp(); 
    $this->mock = m::mock('Illuminate\Database\Eloquent\Model'); // Or better if you mock 'FactureSst' 
    $this->app->instance('FactureSst', $this->mock); 
} 

Это немного сбивает с толку, потому что вы утверждаете абстрактный класс содержит методы ORM, но когда вы вызываете эти методы, вы вызываете их на нагнетаемой Model зависимость, а не на абстрактном классе. Вероятно, это путаница.

Кроме того, если ваши модели расширяются Illuminate\Database\Eloquent\Model, часто лучше просто ввести вашу модель в репозиторий, а не Illuminate\Database\Eloquent\Model. Таким образом, вы также можете воспользоваться любыми функциями отношений, которые у вас установлены в вашей модели внутри вашего репозитория.

+0

Hi , Спасибо за ответ. Как вы сказали, у меня есть абстрактный класс, содержащий методы ORM, поэтому я должен делать вызовы модели, которые мне придется изменить. Я проверю это во вторник, когда вернусь к работе, спасибо за ответ – xonorageous

+0

Просто проверил это, вызвав абстрактные методы репо, а не модель, тесты работают. большое спасибо – xonorageous

0

Если я не ошибаюсь, эта линия

$result = $this->repo->findWithSstAndBdc(30207, 10); 

должно быть на самом деле

$result = $this->mock->findWithSstAndBdc(30207, 10); 

держать Также в виду, вы можете издеваться всю цепочку вызовов (полезно для беглых запросов, как это):

$this->mock->shouldReceive('where->whereHas->get') 
    ->once()->andReturn(/*MAKE A FAKE OBJECT HERE*/); 

Я бы также использовал встроенный foreach PHP() вместо использования $ factures-> each, поскольку он еще одно испытание для проверки.

+0

Привет, спасибо, что ответ. Как предложил я попытался заменить $ this-> репо с $ this-> издеваться, но сейчас я получаю следующее сообщение об ошибке: BadMethodCallException: Метод Mockery_0_FD_Repo_FactureSst_FactureSstInterface :: findWithSstAndBdc() не существует на этом макете объекта – xonorageous

Смежные вопросы