【WIP】PHPUnit로 나 취향의 어서션을 더해 「읽기 쉬운 쓰기 쉬운」테스트를
12891 단어 PHPUnit
@todo 각 클래스의 상세·역할 분담에 대해서 쓴다
현재 업무로 API 애플리케이션을 개발하고 있습니다.
API라는 것으로, 「에러의 형식이 정해져」 있습니다.
그 때, _view에 들어 있는 변수를 취해 그 안의
$codeがXXX
$sub_codeがYYY
$messageがZZZ
세 가지? 그게・・・별로 온화하지 않다고 느낀 것입니다.
※실제로는 좀 더 복잡. 끝이 접혀 있습니다만, 대체로 이런 이미지입니다.
「같은 처리라면」 「같은 쓰는 방법을」 「게다가 가능한 한 간결·일목요연하게」하는 것이 아름답지 않습니까?
그렇다고 해서, 「에러시의 응답의 어설션」을 둥글게 정리해 버리면 편하지 않습니까! ! 라고 생각한 것입니다.
만들고 싶은 것
예를 들면, Twitter의 REST API의 응답의 이미지로, 그 내용을 검사하는 물건! 를 만들어 보자. 라고 하는 상정으로 추천합니다.
{
"errors": [
{"message":"Sorry, that page does not exist","code":34},
{"message":"User not found.","code":50},
{"message":"Sorry, you are not authorized to see this status","code": 179}
]
}
※어디까지나 「예」예요! 실제로는 이것들의 에러가, 하물며 동시에 복수개 돌아올까? 라든지 돌진하는 것은 야생입니다.
cf : Error Codes & Responses — Twitter Developers
이것에 대해,
$this->assertErrorCode(34, $errors, '存在しないはずのページの状態を検知できていない');
$this->assertErrorCode(50, $errors, '存在しないはずのユーザーの状態を検知できていない');
$this->assertErrorCode(179, $errors, 'アクセス資格のないリソースにアクセスできてしまっている');
라든지 할 수 있으면 = 응답을 일일이 디코드해 key/value 체크를 해···라고 쓰는 것보다 슛으로 하기 때문에 「테스트하고 싶은 내용을, 코드에 명료하게 떨어뜨릴 수 있다」입니다.
구현 개요 (PHPUnit API)
공식 doc는 다음과 같습니다. 확실히 언급되었습니다.
-> 맞춤 어설션 만들기
과연, 아무래도
Constraint
matcher
및 TestCase のサブクラス
라는 것이 키워드가 될 것 같네요.··라고는 해도, 개인적으로는 “조금 달리기 기분” 혹은 “약간 오라 붙었다” 기술로는···라고 하는 인상을 받았습니다.
구체적인 예를 원합니다. 원시 코드를 살펴 보겠습니다.
Constraint
assertXxx() 엔티티
오마케:
나는 CakePHP를 평상시 사용하고 있기 때문에 Cake에서의 구현 예도 함께 소개해 둡니다.
구현해 보자.
인터페이스 및 로직
어떤 것이 있으면 좋을까요?
"검사 대상 (json 문자열)"에 대해 "
code
어때요?어리석게 쓰면 이런 느낌으로.
$data = json_decode($json);
if (! $json) {
return false;
}
if (! (property_exists($json, 'code') && property_exists($json, 'message'))) {
return false;
}
return ($json->code === $expected_code, && $json->message === $expected_message);
이것을 「로직」으로서 어설션 메소드의 로직은 constraint에 짜넣는다고 하는 법에 따라 클래스를 정의해 보겠습니다.
구체적으로는 (
message
와) __construct()
matches()
라는 public 메소드를 구현해 두면 같다.class ApiResponse extends PHPUnit_Framework_Constraint
{
// 検査対象となる内容を格納する
private $data;
// expectedとの比較を行う前のフェーズで「失敗」させる事も可能
public function __constuct(string $json)
{
$data = json_decode($json);
if (! $data) {
// FailedErrorを投げることで、任意のタイミングでアサーションを失敗させられる
throw new PHPUnit_Framework_AssertionFailedError('Failed to parse json.');
}
if (! (is_object($json) && property_exists($json, 'code') && property_exists($json, 'message')) {
return false;
}
$this->data = $data;
}
public function matches($expected)
{
// 失敗ならfalse、成功ならtrueを返すだけでOK
return (
$this->data->code === $expected['code']) &&
$this->data->message = $expected['message']
);
}
public toString()
{
return sprintf('%s has not valid code and message.', json_encode($this->data));
}
}
로직은 가능했습니다. 그리고는 「호출원」입니다.
이것이 「TestCase의 서브 클래스」라는 것이 됩니다.
class AssertApiResponse extends PHPUnit_Framework_TestCase
{
public function assertApiResponse($code, $messsage, $content, $message = '')
{
$this->assertThat(compact('code', 'message'), new ApiResponse($content), $message);
}
}
그리고는, 이런 형태로 취득한 응답에 대한 어설션이 가능하게 됩니다.
$error = $response['errors'][0];
$this->assertApiResponse(34, 'Sorry, that page does not exist', $error, '存在しないはずのページの状態を検知できていない');
Reference
이 문제에 관하여(【WIP】PHPUnit로 나 취향의 어서션을 더해 「읽기 쉬운 쓰기 쉬운」테스트를), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/o0h/items/d2272c80d6ab88f3df8c텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)