[PHPUnit] มาเทส RESTful ด้วย Codeception กันเถอะเหล่า PHP โปเกม่อนทั้งหลาย

พึ่งลองเขียนได้สองวันฮับ เลยอยากจะแชร์ไว้เป็นประสบการณ์สักหน่อย

เริ่มจากไปที่ http://codeception.com/quickstart แล้วอยากจะใช้วิธีไหนเลือกได้ตามสบายเลยครับ แต่ในบทความนี้ผมขออนุญาตใช้ผ่าน codecept.phar ตามปกติก็แล้วกันนะครับ Composer มีปัญหาเชี่ยไรของมันก็ไม่รู้ T^T

ว่าแล้วก็ทำตาม Quickstart เลยก็แล้วกันนะครับ เริ่มจากดาวโหลดไฟล์ codecept.phar ลงมาด้วย
wget http://codeception.com/codecept.phar

จากนั้นก็สั่งให้มันสร้าง test suites กับส่วนอื่นๆ ที่จำเป็นในการเทสให้เรา
php codecept.phar bootstrap

จากนั้นให้เข้าลิ้งนี้ครับ http://codeception.com/docs/10-WebServices จะเห็นว่ามันมีให้สร้าง api suites(codeception มันจะสร้างให้เองเลย... สบายเจงๆ) ไม่ต้องรอให้ใครมาตัดริบบิ้นแล้วครับ จัดไป!!!
php codecept.phar generate:suite api

เสร็จแล้วก็มาดูที่ตัว config ของ api ที่เราจะเทสกันครับ...มันจะอยู่ในไฟล์ api.suite.yml บาง Modules ต้องมาเซ็ตในนี้ฮับ อย่างเช่น Doctrine2, Facebook ฯลฯ ต้องไปเช็กใน Modules กันเอง จากนั้นก็ทำการ Build ครับด้วย
php codecept.phar build

มันก็จะไปถึงเอา Modules ต่างๆ มาไว้ใน tests/api/ApiTester.php ให้เอง เย้ เย ...
ขั้นตอนต่อไปก็ทำการสร้างเทสครับ อย่างเช่น
php codecept.phar generate:cept api CreateUser
* ย่อคำว่า generate เหลือแค่ g ได้

เราจะได้ไฟล์ที่ชื่อว่า CreateUserCept.php มาครับซึ่งมันจะอยู่ใน tests/api/ ถ้าอ่านตาม Doc ตัวอย่างจะเป็นแบบนี้

$I = new ApiTester($scenario);
$I->wantTo('create a user via API');
$I->amHttpAuthenticated('service_user', '123456'); $I->haveHttpHeader('Content-Type', 'application/x-www-form-urlencoded');
$I->sendPOST('users', ['name' => 'davert', 'email' => 'davert@codeception.com']);
$I->seeResponseCodeIs(200);
$I->seeResponseIsJson();
$I->seeResponseContains('{"result":"ok"}');

จริงๆ มันแทบจะเป็นภาษาคนแล้วนะ... อ่านยังไงก็เข้าใจอ่ะ ....

$I->wantTo('create a user via API');
ต้องการจะทำอะไรในการเทสครั้งนี้ก็เขียนลงไปครับ ตอนเวลาเรา run แล้วอ่านจะได้ไม่สับสน

$I->haveHttpHeader('Content-Type', 'application/x-www-form-urlencoded'); 
อันนี้เราจะส่ง Method เป็น POST ก็เลยต้องเขียนบอกไว้ใน Header ซะหน่อยว่าตูจะส่งเป็น Form นะเว้ยเห้ย

$I->sendPOST('users', ['name' => 'davert', 'email' => 'davert@codeception.com']);
ส่งเป็น POST อะไรก็ว่ากันไปตามนั้น ซึ่ง sendGET, sendPUT, sendDELETE ก็มี :)

$I->seeResponseCodeIs(200);
ดูว่าค่าที่ส่งกลับมามี Status เป็น 200 รึป่าว

$I->seeResponseIsJson();
ดูว่าค่าที่ส่งกลับมาเป็น json รึป่าว

$I->seeResponseContains('{"result":"ok"}');
ดูว่าไอ้ json ที่ส่งกลับมานั้นมีค่าตามที่เรากำหนดนี้รึป่าว

เสร็จแล้วก็ตบท้ายด้วยการรันมันครับด้วย
php codecept.phar run

############################
เพิ่มเติม1
ถ้า run ตามปกติ มันจะเทสหมดเลยครับไม่ว่าจะเป็น acceptance, api, functional, unit วิชาลัดใช้เทสเฉพาะ api ก็คือ
php codecept.phar run api

ถ้าอยากดู Response เวลาเรา var_dump ก็สามารถใส่ --debug เข้าไปด้านหลังสุดครับ เช่น
php codecept.phar run api --debug
############################

ถ้าผลลัพธ์ออกมาไม่ถูกต้องตามที่เราเขียนเทสเอาไว้มันก็จะขึ้นแดงๆ แบบนี้ ตัวอย่างเช่น ค่าที่Response กลับมาไม่เป็น json, มี Error 404 ฯลฯ

ถ้าเทสผ่านก็จะขึ้นเขียวๆ แบบนี้

############################
เพิ่มเติม2
จากที่เขียนมาผมคิดว่ามีส่วนที่จำเป็นต้องใช้เพิ่มคือ grabDataFromJsonResponse ครับ อย่างเช่น เราอยากเอา id จาก json ที่ Response มาไปทำเทสอย่างอื่นต่อสามารถเรียกใช้ แบบนี้ได้ครับ
$id = $I->grabDataFromJsonResponse('id');

อีกตัวคือ seeResponseContainsJson ครับ... โดยส่วนตัวผมคิดว่าใช้งานได้ง่ายกว่า seeResponseContains เยอะเลยก็คือ seeResponseContains มันจะเช็กตาม format นั้นเปะๆ เลยครับ แต่กับ seeResponseContainsJson เองเราสามารถเช็กเป็นบางตัวได้ แต่ต้องเขียนเช็กให้เป็นแบบ Array เท่านั้น ตัวอย่างเช่น ผมได้ Response กลับมาเป็นแบบนี้

{"id":"yh7352gdjt85ywgy6e", "name":"Test name", "detail":"Test detail", "time":"2015-01-26 16:38:00" }

แต่ผมต้องการเช็กเฉพาะ id เท่านั้นพอผมสามารถเขียนได้ดังนี้ครับ
$I->seeResponseContainsJson([
    'id' => 'yh7352gdjt85ywgy6e'
]);

Q: แล้วถ้า id มันถูก Random ขึ้นมาล่ะ?
A: ก็เขียนลักไก่แบบนี้ได้ครับ
$id = $I->grabDataFromJsonResponse('id');
$I->seeResponseContainsJson([
    'id' => $id
]);

Q: แล้วถ้าต้องการเทสเฉพาะ id, detail, time ล่ะ?
A: ก็เขียนเป็นแบบนี้ได้ครับ
$id = $I->grabDataFromJsonResponse('id');
$I->seeResponseContainsJson([
    'id' => $id,
    'detail' => 'Test name',
    'time' => '2015-01-26 16:38:00'
]);

Q: ต้องการเทสเฉพาะไฟล์ทำยังไงดี?
A: เขียนแบบนี้ครับ
php codecept.phar run tests/api/CreateUserCept.php --debug

############################

ข้อดี เรารู้ว่าเทสอะไรไปแล้วบ้างปัญหาที่เจอจะเป็นแบบ spiral in เพราะเรามี test case
ข้อเสีย เสียเวลาเขียนโค้ดเพิ่ม
ปล. ก๊อบคนอื่นเค้ามา เห็นเค้าว่ากันแบบนั้น... ฮ่าาาาาาาา

ประมาณนี้ครับ หวังว่าจะเป็นประโยชน์สำหรับคนทำเว็บไม่มากก็น้อยนะฮับ เย้ เย

Comments