PHP로 HTTP 서버 구현하기 - 06 - Request 분리, autoload, PHPUnit
Request 분리
autoload
우선 클라이언트로부터 받은 request 메시를 분석하는 클래스부터 만들기로 했다.
Project root에 libs
디렉토리를 만들어 놓고, 여기에 Request
라는 클래스를 하나 만들어야겠다.
그럼 autoload도 적용해야 하니 composer를 이용해야겠다.
대충 composer init
해서 파일을 만들고, libs
디렉토리를 psr-4 기반으로 autoload 하도록 설정해주자.
{ |
이제 libs
디렉토리 아래 Request
클래스를 하나 만들고
|
server.php
상단에 autoload용 코드를 심고, Request를 로드해보자.
|
일단 autoload는 잘 동작한다. OK.
server.php
테스트용으로 넣었던 쓸데 없는 코드는 이제 지우고,
Request
클래스에 사용자 입력을 분석하고 응답을 만들어내는 역할을 맡기려고 한다.
서버 소스는 아래와 같이 바뀌었다.
|
이전 소스에서 index.html
을 읽기 위해 아래와 같이 상대 위치로 하드코딩해서 썼었다.
//...생략... |
처리 로직이 서버 소스를 떠나면 index.html
파일을 여는 fopen을 어디서 처리할 지 아직 확신이 없다. 계속 바뀔지 모른다.
그래서 프로젝트의 최상위 경로를 PROJECT_ROOT
라는 상수로 지정했다.
그리고 주요 처리 로직을 들어내고 Request
클래스에 클라이언트가 보낸 문자열을 전달하고,
getResponse()
메소드로 받은 문자열을 그대로 클라이언트에 전달한다.
이제 당분간 이쪽 소스를 건드릴 일은 없어 보인다.
Request.php
이 클래스를 사용하는 곳(server.php)을 보면 Request
클래스의 역할은 크게 두가지다.
- 클라이언트가 보낸 문자열을 생성자로 받는 것
getResponse()
메소드로 처리 결과를 리턴하는 것
server.php
의 소스를 가능한 건드리지 않고 조심히 들고와보자.
|
거의 동일하다.
어려울 게 없으니 서버 실행!
테스트
이전의 파일 하나짜리 서버와 동일하게 동작한다.
잘 돌아는 가는데 어쩐지 마음이 헛헛하다.
(가을인가)
계속 이렇게 테스트를 해야하나?
매번 뭔가 수정하고 php ./app/server.php
를 다시 실행해야 하나?
이제 개발 시작할 분석 로직은 그냥 스트링을 던져주고 결과만 잘 나오면 되는데.
소파에 반쯤 누워 맥주 한잔 들이키며 이 막장 드라마를 구경하는 중급 개발자라면 ‘유닛 테스트를 걸라고, 멍청아’라고 소리칠 것만 같다.
넣어주지 뭐.
PHPUnit
PHPUnit을 가져와야 할텐데, composer.json
에 추가하기 보다는 composer require
을 사용하기로 한다.
콘솔을 열고
composer require --dev phpunit/phpunit ^6.4
- “개발에서 쓰려고 하는데 대충 6.4 정도면 될 것 같아요”
최신 버전이 6.4라서 명시했고, 7.0 전까지는 써도 별 탈 없을 것이다.
업데이트가 완료되면 PHPStorm에 실행 환경을 설정한다.
테스트 범위 설정이나 그룹화를 위해 XML로 설정하기로 한다.
프로젝트 root에 phpunit.xml
파일을 만들고 아래와 같이 입력.
<phpunit bootstrap="vendor/autoload.php"> |
테스트를 돌리기 전 특별히 bootstrap할 게 없으므로 vendor/autoload.php
를 bootstrap에 명시했고,
testsuite 명은 나중에 바뀌겠지만 일단 대충 넣고,
tests
라는 디렉토리에 있는 Test.php로 끝나는 파일(예: parseTest.php)을 모두 검사하도록 했다.
PHPUnit with PHPStorm
다른 에디터를 쓰는 분들은 다른 각자 알아서 찾아보면 될 것이고, 여기서는 간단히 PHPStorm에서 설정하는 법만 적어본다.
Run | Edit Configurations
메뉴에서 +
버튼을 눌러 PHPUnit
선택.
Test Runner > Test Scope
을 `Definded in the configuration file’을 선택한다.
바로 아랫줄 제일 오른쪽에 보이는 설정 버튼을 누르면 Test Frameworks
설정 창이 나온다.
(만약 처음 설정/실행한다면 창 아래쪽에서 configuration file에 문제가 있으니 수정하라고 Fix
버튼이 보일 수도 있다. 이걸 눌러도 같은 창이 나온다.)
+
버튼을 눌러 Configuration type을 PHPUnit Local로 추가한 후,
PHPUnit library > Use Composer autoloader 선택하고 Path to script는 …
버튼을 눌러 자신의 vendor/autoload.php
을 선택하면 된다.
그 아래 Test Runner 옵션에서는 Default configuration file
을 체크하고 앞서 만든 phpunit.xml
을 선택한다.
그리고 실행!
테스트를 작성하지 않았으므로 No tests executed!
같은 메시지가 보이면 정상이다.
실행창에서 Toggle auto-test를 눌러 놓으면 뭔가 수정이 될 때마다 테스트가 실행된다.
하지만 개발하다보면, 주석을 넣는다거나 공백을 삽입하는데도 test가 실행되므로 종종 눈엣가시가 된다.
이럴 때는 AutoTest Delay값을 늘려주면 좀 낫다.
나중에 테스트가 엄청 많아지면 현재 개발하는 모듈 이외의 클래스도 단위테스트가 돌게 될텐데, 이 때는 phpunit.xml
에서 테스트 단위를 나누면 된다. 하지만 예상컨대 이 프로젝트에선 그렇게까지 테스트가 많아질 것 같지 않다.
결론
이제부터는 뭔가 추가/수정할 때마다 미리 테스트를 만들고 실패하는 것을 확인하고 이를 만족하는 기능을 개발하게 될 것이다.
현재 추가/수정하는 코드가 시스템을 망가뜨리지 않는다는 최소한의 보장을 받을 수 있다.
하지만 서버 코드의 많은 부분이 file이나 directory를 읽어야 하는데, 이런 부분은 unit test 만으로 해결 안될 수 있다.
뭐가 어려운지는 이런 글을 보고 예습을 하는 것도 좋다.
참고
http://www.php-fig.org/psr/psr-4/
https://getcomposer.org/doc/01-basic-usage.md
http://xpressengine.github.io/Composer-korean-docs/
https://getcomposer.org/doc/articles/versions.md#caret-version-range-
https://phpunit.de/index.html
https://www.jetbrains.com/help/phpstorm/testing-with-phpunit.html
http://jwchung.github.io/testing-oh-my