저는 테스트를 잘하고 싶어서 꽤 시간을 많이 들여 학습한 편입니다. 아직도 잘하진 못하지만 왠만하면 테스트를 작성하려고 하고, 테스트가 없으면 좀 불안해하는 편입니다. 작년에 한 프로젝트에 참여했었는데, 그때도 가장 먼저 한 일이 테스트를 작성한 일이었습니다. 주요 기능들을 커버하는 테스트를 작성하기 까지 꽤 오랜 시간이 필요했습니다. 제이슨 맥크레리(Jason McCreary)가 기존 라라벨 애플리케이션 테스트에 소요되는 시간 줄이기(Lowering the time cost of testing existing Laravel applications)라는 제목의 글을 썼기에 반가운 마음에 요약 해봤습니다. 이 글의 내용을 미리 알고 있었다면 덜 고생했을텐데 아쉽네요. ㅎㅎ
제이슨 맥크레리는 최근에 다른 사람과 페어프로그래밍을 하게되서 기존 애플리케이션에 테스트를 작성할 일이 있었다고 합니다. 그때 시간이 무척 많이 들었는데, 테스트를 준비하는데 드는 시간이 많았다고 합니다. 기존 라라벨 애플리케이션에서 테스트를 시작하기까지 다음과 같은 작업이 필요하다고 합니다.
이 모든 작업을 마친다고 해도 아직 실질적인 테스트는 한 줄도 작성하지 않은 것입니다. 시간은 시간대로 썼는데 성과가 눈에 드러나지 않는 일입니다. 테스트 준비에 소요되는 시간을 줄이는 방법을 몇가지 소개합니다.
기존 애플리케이션에 테스트를 추가할 때는 우선 HTTP 테스트만 충실히 작성해도 충분합니다. 어차피 이미 잘 동작하는 애플리케이션이기 때문에 유닛 테스트가 급한 상황은 아닙니다. 라우트에서 클로저로 처리를 하는 경우도 있지만 대부분의 요청은 컨트롤러로 처리할 겁니다. 라라벨에서는 컨트롤러 파일명이 Controller
로 끝나는게 관례입니다. 이를 활용해서 아래와 같이 한 번에 모든 컨트롤러용 테스트를 만들 수 있습니다.
find app/Http/Controllers -type f -name '*Controller.php' -exec sh -c 'php artisan make:test $(dirname "${1:4}")/$(basename "$1" .php)Test' sh {} \;
이로서 앞서 말한 다섯가지 준비 사항 중 첫번째 항목이었던 “다양한 컴포넌트에 대한 테스트 클래스 만들기”에 드는 시간을 많이 아낄 수 있을 것 같습니다.
테스트를 준비할 때 가장 시간이 많이 드는건 모델 팩토리를 작성하는 것입니다. 라라벨 테스트 팩토리 제너레이터는 마르셀 포시오트가 만든 패키지로써, 모든 모델에 대한 팩토리를 한 방에 만들어줍니다. 단순히 팩토리 파일을 만드는 것 뿐만 아니라 데이터베이스 스키마를 분석해서 모델 팩토리의 내용도 자동으로 작성해줍니다. 심지어 모델간의 관계도 분석해서 알아서 처리해줍니다. 아래와 같은 테이블이 있다면
Schema::create('lessons', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->integer('ordinal');
$table->unsignedBigInteger('course_id');
$table->timestamps();
});
이 패키지는 다음과 같은 모델 팩토리를 자동으로 만들어줍니다.
/* @var $factory \Illuminate\Database\Eloquent\Factory */
use Faker\Generator as Faker;
$factory->define(App\Lesson::class, function (Faker $faker) {
return [
'name' => $faker->name,
'ordinal' => $faker->randomNumber(),
'course_id' => function () {
return factory(App\Course::class)->create()->id;
},
];
});
이 패키지로 앞서 언급한 다섯가지 준비 사항 중 두번째와 세번째 단계에 드는 시간을 아낄 수 있습니다. 모델이 많으면 많을수록 엄청나게 시간을 아낄 수 있겠네요.
제이슨 맥크레리는 여기서 한 발 더 나아가고 싶었나봅니다. 테스트 준비 작업 뿐 아니라 실제 테스트를 작성하는 시간도 줄이고 싶다고 합니다. 이를 위해 Test Generator Shift 라는 것을 만들기 시작했다고 하네요. 라우트 정의와 컨트롤러 메서드 시그니처를 활용해서 테스트와 팩토리를 자동으로 생성되게 할 계획이라고 합니다. 현재 알파 테스트를 마쳤다고 하네요.
예를들어 아래와 같은 라우트가 있다면
Route::get('promotions/{code}', 'CouponController@show');
The Test Generator Shift는 다음과 같은 HTTP 테스트를 만들어줍니다.
<?php
namespace Tests\Http\Controllers;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class CouponControllerTest extends TestCase
{
use RefreshDatabase;
/** @test */
public function show_returns_an_ok_response()
{
$this->markTestIncomplete('This test case was generated by Shift and needs review.');
$coupon = factory(\App\Coupon::class)->create();
$this->get('promotions/' . $coupon->code);
$response->assertOk();
// TODO: perform additional assertions...
}
}
8월 중에 릴리즈하는 것을 목표로 한다고 하네요. 정말 기대됩니다.
기존 애플리케이션에 테스트를 추가하고 싶었지만 엄두가 안나셨던 분들은 오늘 소개한 스크립트와 라라벨 테스트 팩토리 제너레이터, 그리고 앞으로 나올 The Test Generator Shift를 활용하면 한결 수월하게 시작할 수 있지 않을까 싶습니다.
===
어느새 7월호의 마지막 글이네요. 컨텐트가 여러분들께 도움이 되었는지 모르겠네요. 1일 1식 라라벨 프로젝트를 실행할 수 있도록 힘을 실어주셔서 정말 감사했습니다. 8월에도 쏠쏠한 내용들 전달하도록 노력하겠습니다.
1일 1식 라라벨
2019년 7월 31일
메쉬 코리아 개발자. 바쁜 팀장님 대신 알려주는 신입 PHP 개발자 안내서를 쓰고, 클린 아키텍처 인 PHP를 번역했습니다. 처음부터 제대로 배우는 라라벨(Laravel Up & Running 2nd Edition)을 번역했습니다.