Test Driven Laravel 02 - Book:Update 테스트 코드 구현 / 리팩토링
31 Dec 2019 | PHP TDD Laravel coderstapeCoder’s tape의 Test Driven Laravel 강의 를 듣고 정리한 포스팅 입니다.
1. Update 테스트 코드 구현
데이터를 업데이트 시키는 기본 코드 작성
/** @test */
public function a_book_can_be_updated()
{
$this->withoutExceptionHandling();
$this->post('/books', [
'title' => 'cool book title',
'author' => 'harry'
]);
$response = $this->patch('/books', [
'title' => 'New Title',
'author' => 'Victor',
]);
$this->assertEquals('New Title', Book::first()->title);
$this->assertEquals('harry', Book::first()->author);
}
테스트를 동작시키면, 라우트에 대하여 PATCH가 지원되지않는다는 에러 발생. 따라서 라우트를 추가시킴.
//Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException : The PATCH method is not supported for this route. Supported methods: POST.
Route::patch('/books', 'BooksController@update');
컨트롤러에 update 메소드 기본 코드 작성.
public function update()
{
$data = request()->validate([
'title'=>'required',
'author'=> 'required',
]);
}
하지만, 현재 코드로도 여전히 에러가 발생한다. 업데이트 로직을 구현하기 위해서는 어떤 데이터에 대하여 업데이트를 할 건지를 명시해줘야한다. 이때 데이터의 id값을 사용.
/** @test */
public function a_book_can_be_updated()
{
$this->withoutExceptionHandling();
$this->post('/books', [
'title' => 'cool book title',
'author' => 'harry'
]);
// book 클래스 인스턴스 추가
$book = Book::first();
//id값을 variable routing으로 사용
$response = $this->patch('/books/' . $book->id, [
'title' => 'New Title',
'author' => 'Victor',
]);
라우트와 컨트롤러를 적절히 수정시킴.
Route::patch('/books/{book}', 'BooksController@update');
public function update(Book $book) // route model binding
{
$data = request()->validate([
'title'=>'required',
'author'=> 'required',
]);
$book->update($data);
}
2. Create & Update 테스트 코드 및 로직 구현
결과적으로, 데이터를 생성하고 업데이트하는 로직을 성공적으로 아래와 같이 구현 완료
- 데이터 생성
- 제목, 작가명 유효성 검증
- 데이터 업데이트
// BooksController.php
namespace App\Http\Controllers;
use App\Book;
use Illuminate\Http\Request;
class BooksController extends Controller
{
public function store()
{
$data = request()->validate([
'title'=>'required',
'author'=> 'required',
]);
Book::create($data);
}
public function update(Book $book)
{
$data = request()->validate([
'title'=>'required',
'author'=> 'required',
]);
$book->update($data);
}
}
//web.php
Route::post('/books', 'BooksController@store');
Route::patch('/books/{book}', 'BooksController@update');
// BookManagementTest.php
namespace Tests\Feature;
use App\Book;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class BookReservationTest extends TestCase
{
use refreshDatabase;
/** @test */
public function a_book_can_be_added_to_the_library()
{
$this->withoutExceptionHandling();
$response = $this->post('/books', [
'title' => 'cool book title',
'author' => 'harry'
]);
$response->assertOk();
$this->assertCount(1, Book::all());
}
/** @test */
public function a_title_is_required()
{
// $this->withoutExceptionHandling();
$response = $this->post('/books', [
'title' => '',
'author' => 'harry'
]);
$response->assertSessionHasErrors('title');
}
/** @test */
public function an_author_is_required()
{
$response = $this->post('/books', [
'title' => 'cool book title',
'author' => ''
]);
$response->assertSessionHasErrors('author');
}
/** @test */
public function a_book_can_be_updated()
{
$this->withoutExceptionHandling();
$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);
}
}
3. 리팩토링
유효성 검증하는 코드가 반복적으로 사용되고 있음. 이 코드를 extract 시켜 별도의 메소드로 구현
$data = request()->validate([
'title'=>'required',
'author'=> 'required',
]);
public function store()
{
$data = $this->validateRequest();
Book::create($data);
}
public function update(Book $book)
{
$data = $this->validateRequest();
$book->update($data);
}
public function validateRequest()
{
return request()->validate([
'title' => 'required',
'author' => 'required',
]);
}
$data를 인라인으로 변경하는 것도 가능
// before
$data = $this->validateRequest();
$book->update($data);
// after
$book->update($this->validateRequest());
리팩토링 최종 완성된 코드는 다음과 같음.
class BooksController extends Controller
{
public function store()
{
Book::create($this->validateRequest());
}
public function update(Book $book)
{
$book->update($this->validateRequest());
}
public function validateRequest()
{
return request()->validate([
'title' => 'required',
'author' => 'required',
]);
}
}
Comments