Test Driven Laravel 03 - Book:Delete 테스트 코드 구현 / Redirect 리팩토링
01 Jan 2020 | PHP TDD Laravel coderstapeCoder’s tape의 Test Driven Laravel 강의 를 듣고 정리한 포스팅 입니다.
1. Delete 테스트 코드 작성
데이터를 삭제하는 테스트 케이스도 유사한 방식으로 생성 가능
/** @test */
public function a_book_can_be_deleted()
{
$this->withoutExceptionHandling();
$this->post('/books', [
'title' => 'cool book title',
'author' => 'harry'
]);
$book = Book::first();
$this->assertCount(1, Book::all());
$response = $this->delete('/books/' . $book->id);
$this->assertCount(0, Book::all());
}
DELETE 메소드 라우터에 추가
Route::delete('/books/{book}', 'BooksController@destroy');
컨트롤러에 destroy 메소드 추가
public function destroy(Book $book)
{
$book->delete();
}
2. Delete - Redirect
데이터가 삭제 된 이후, index페이지로 리다이렉트 설정
// BooksController@a_book_can_be_deleted
$response = $this->delete('/books/' . $book->id);
$this->assertCount(0, Book::all());
$response->assertRedirect('/books');
// Bookscontroller.php
public function destroy(Book $book)
{
$book->delete();
return redirect('/books');
}
3. Update - Redirect
데이터를 업데이트한 이후, show(상세페이지)로 리다이렉트 설정
/** @test */
public function a_book_can_be_updated()
{
$this->post('/books', [
'title' => 'cool book title',
'author' => 'harry'
]);
$book = Book::first();
$response = $this->patch('/books/' . $book->id, [
'title' => 'New Title',
'author' => 'victor',
]);
$this->assertEquals('New Title', Book::first()->title);
$this->assertEquals('victor', Book::first()->author);
// redirect 추가
$response->assertRedirect('/books/' . $book->id);
}
컨트롤러내 update 메소드에서도 리다이렉트 추가
public function update(Book $book)
{
$book->update($this->validateRequest());
return redirect('/books/' . $book->id);
}
4. Create(Store) Redirect
동일한 방법으로 데이터 생성 후, show(상세페이지)로 리다이렉트 설정
public function a_book_can_be_added_to_the_library()
{
$response = $this->post('/books', [
'title' => 'cool book title',
'author' => 'harry'
]);
// 인스턴스 저장($book->id를 넘기기 위해 필요)
$book = Book::first();
$response->assertOk();
$this->assertCount(1, Book::all());
// 리다이렉트 설정
$response->assertRedirect('/books/' . $book->id);
}
public function store()
{
$book = Book::create($this->validateRequest());
return redirect('/books/' . $book->id);
}
테스트를 동작시키면, 302 에러 발생함. 따라서 200 응답을 반환하는 코드인 아래 코드를 삭제해줘야함.
//Response status code [302] does not match expected 200 status code.
$response->assertOk(); // 제거할 것
5. 리다이렉트 리팩토링 (1)
상세페이지(show)로 리다이렉트시키는 아래의 코드가 반복적으로 사용되고 있음. 이를 모델의 메소드로 구현하여 리팩토링을 할 수 있음.
Book@path
메소드 구현
return redirect('/books/' . $book->id);
class Book extends Model
{
protected $guarded = [];
public function path()
{
return '/books/' . $this->id;
}
}
public function store()
{
$book = Book::create($this->validateRequest());
// return redirect('/books/' . $book->id);
return redirect($book->path());
}
BookReservationTest.php내에서 기존의 리다이렉트 포맷을 갖고 있는 코드를 업데이트 시킴
// before
$response->assertRedirect(('/books/' . $book->id));
// after
$response->assertRedirect($book->path());
6. 리다이렉트 리팩토링 (2) - optional
헬퍼 메소드를 통해, 라우트의 엔드포인트를 book/{id}
-> book/{id}-{title}
로 변경 시킬 수 있음.
Str::slug()
메소드는 주어진 문자열로부터 URL에 알맞은 “slug”를 생성합니다
use Illuminate\Support\Str;
public function path()
{
return '/books/' . $this->id . '-' . Str::slug($this->title);
}
엔드포인트 재 설정
Route::patch('/books/{book}-{slug}', 'BooksController@update');
그러나, 업데이트 부분에서 여전히 변경 전 title을 url에 반영하고 있기 때문에 에러가 발생함. 따라서 새롭게 업데이트된 title로 redirect 시키도록, 인스턴스를 새로고침하는 fresh()
메소드를 추가.
$book = Book::first();
$response = $this->patch($book->path(), [
'title' => 'New Title',
'author' => 'victor',
]);
$this->assertEquals('New Title', Book::first()->title);
$this->assertEquals('victor', Book::first()->author);
// fresh() 추가
$response->assertRedirect($book->fresh()->path());
BookReservationTest.php 파일을 BookManagementTest.php파일로 이름 변경
Comments