해리의 데브로그

Test Driven Laravel 03 - Book:Delete 테스트 코드 구현 / Redirect 리팩토링

|

Coder’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