2014-09-17 1 views
2

Хорошо, поэтому я довольно новичок как для модульного тестирования, издевательства, так и для laravel. Я пытаюсь выполнить тестирование моего контроллера ресурсов, но я застрял в функции обновления. Не уверен, что я делаю что-то неправильно или просто ошибаюсь.Laravel & Mockery: модуль тестирует метод обновления без попадания в базу данных

Вот мой контроллер:

class BooksController extends \BaseController { 

    // Change template. 
    protected $books; 

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

    /** 
    * Store a newly created book in storage. 
    * 
    * @return Response 
    */ 
    public function store() 
    { 
     $data  = Input::except(array('_token')); 
     $validator = Validator::make($data, Book::$rules); 

     if($validator->fails()) 
     { 
      return Redirect::route('books.create') 
       ->withErrors($validator->errors()) 
       ->withInput(); 
     } 

     $this->books->create($data); 

     return Redirect::route('books.index'); 
    } 

    /** 
    * Update the specified book in storage. 
    * 
    * @param int $id 
    * @return Response 
    */ 
    public function update($id) 
    { 
     $book  = $this->books->findOrFail($id); 
     $data  = Input::except(array('_token', '_method')); 
     $validator = Validator::make($data, Book::$rules); 

     if($validator->fails()) 
     { 
      // Change template. 
      return Redirect::route('books.edit', $id)->withErrors($validator->errors())->withInput(); 
     } 

     $book->update($data); 

     return Redirect::route('books.show', $id); 
    } 
} 

А вот мои тесты:

public function testStore() 
{ 
    // Add title to Input to pass validation. 
    Input::replace(array('title' => 'asd', 'content' => '')); 

    // Use the mock object to avoid database hitting. 
    $this->mock 
     ->shouldReceive('create') 
     ->once() 
     ->andReturn('truthy'); 

    // Pass along input to the store function. 
    $this->action('POST', 'books.store', null, Input::all()); 

    $this->assertRedirectedTo('books'); 
} 

public function testUpdate() 
{ 
    Input::replace(array('title' => 'Test', 'content' => 'new content')); 

    $this->mock->shouldReceive('findOrFail')->once()->andReturn(new Book()); 
    $this->mock->shouldReceive('update')->once()->andReturn('truthy'); 

    $this->action('PUT', 'books.update', 1, Input::all());  

    $this->assertRedirectedTo('books/1'); 
} 

Вопрос в том, когда я делаю это так, я получаю Mockery\Exception\InvalidCountException: Method update() from Mockery_0_Book should be called exactly 1 times but called 0 times. из-за $book->update($data) в мой контроллер. Если бы я должен был изменить его на $this->books->update($data), это было бы неправильно издевательством, и база данных не была бы затронута, но при использовании функции из frontend она обновила бы все мои записи.

Думаю, я просто хочу знать, как насмехаться $book-object properly.

Я достаточно ясно? Дайте мне знать иначе. Благодаря!

+0

Сначала я думал, что ваш '$ this-> book' был [хранилище] (http://culttt.com/2013/07/08/creating-flexible-controllers-in-laravel-4- using-repositories /), но, глядя ближе, он больше похож на модель Eloquent. Это правильно? –

+0

Правильно. Я думал об использовании репозиториев, но решил, что это вызовет у меня слишком много путаницы. – Mattias

+0

Проблема в том, что это одна из основных причин, по которой люди используют репозитории: это делает тестирование намного проще. –

ответ

1

Попробуйте издеваться над методом findOrFail, чтобы не возвращать new Book, но вместо этого возвращать объект-макет, на котором есть метод обновления.

$mockBook = Mockery::mock('Book[update]'); 
$mockBook->shouldReceive('update')->once(); 
$this->mock->shouldReceive('findOrFail')->once()->andReturn($mockBook); 
+0

Вы, добрый сэр, спаситель. Это сделало трюк для меня, и это даже заставляет. Благодаря! – Mattias

+0

np, рад я мог бы помочь :) –

+0

хорошая идея для продукта: Apple MockBook ;-) –

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

  • Нет связанных вопросов^_^