Sử dụng Codeception để kiểm thử mã PHP
Mục tiêu
- Cài đặt và cấu hình Codeception
- Viết mã kiểm thử để đơn giản hóa quá trình phát triển và tối đa hóa sự ổn định và khả năng bảo trì
Các loại kiểm thử
1. Kiểm thử đơn vị (Unit Testing - UT)
- Thực thi một đoạn mã tách biệt khỏi phần còn lại của mã nguồn
- Đưa ra các khẳng định về hành vi của mã
- Mô tả các trường hợp sử dụng mong đợi
2. Kiểm thử chức năng (Functional Testing - FT)
- Gửi yêu cầu đến ứng dụng (từ phía khách hàng)
- Đưa ra các khẳng định về giá trị trả về
- Mô tả hành vi mong đợi của ứng dụng
- Tùy thuộc vào framework
3. Kiểm thử dịch vụ Web
- Gửi yêu cầu API thông qua HTTP client
- Đưa ra các khẳng định về giá trị trả về của API
- Mô tả hành vi của API
Yêu cầu hệ thống
- PHP 5.4+
- Mở rộng json
- Mở rộng mbstring
- Mở rộng xdebug (để tạo báo cáo độ bao phủ)
Cài đặt và cấu hình xdebug Phiên bản được khuyến nghị: 2.6.1
wget https://pecl.php.net/get/xdebug-2.6.1.tgz
tar xvf xdebug-2.6.1.tgz
cd xdebug-2.6.1
/path/to/phpize
./configure --enable-xdebug
make
make install
Thêm dòng sau vào file php.ini:
zend_extension="/wherever/you/put/it/xdebug.so"
Kiểm tra cài đặt:
php -i | grep xdebug
Cài đặt, cấu hình và chạy Codeception
wget http://codeception.com/codecept.phar # Không cần giải nén
php codecept.phar help # Hiển thị tài liệu trợ giúp
php codecept.phar bootstrap # Tạo thư mục test và file codeception.yml trong thư mục hiện tại
php codecept.phar build # Tạo các lớp cần thiết từ cấu hình, chạy mỗi khi thay đổi cấu hình
php codecept.phar run {suite_name} # Chạy tất cả nếu không chỉ định suite name
php codecept.phar run api ThingTest.php
php codecept.phar run api ThingTest.php:method
Ví dụ cấu hình và mã nguồn Địa chỉ: https://github.com/wdy1184/CodeceptionExampleWithYii2
Định dạng mã kiểm thử Codeception hỗ trợ ba cách viết mã kiểm thử:
- Cept: Một file kiểm thử độc lập, có thể chứa một quy trình kiểm thử.
- Cest: Một file class, nhiều kiểm thử được viết trong một class.
- PHPUnit: Hỗ trợ định dạng của PHPUnit.
Tích hợp với Yii2
Cấu hình: _bootstrap.php
<?php
defined('APP_PATH') or define('APP_PATH', dirname(dirname(__FILE__)));
// Đăng ký tự động tải Composer
// Bao gồm file lớp Yii
require(__DIR__ . '/../../psservice/libs/envFun.php');
require(__DIR__ . '/../../vendor/autoload.php');
// Cấu hình biến môi trường
defined('YII_DEBUG') or define('YII_DEBUG', getYaconfEnv('YII_DEBUG'));
defined('YII_ENV') or define('YII_ENV', getYaconfEnv('YII_ENV'));
defined('YII_ENABLE_ERROR_HANDLER') or define('YII_ENABLE_ERROR_HANDLER', getYaconfEnv('YII_ENABLE_ERROR_HANDLER'));
require(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');
// Tương thích ngược với các file cũ
require(__DIR__ . '/../../config/errorCode.php');
require(__DIR__ . '/../../config/constant.php');
Yii::setAlias('@backend', dirname(dirname(__DIR__)) . '/backend');
Yii::setAlias('@console', dirname(dirname(__DIR__)) . '/console');
Yii::setAlias('@psservice', dirname(dirname(__DIR__)) . '/psservice');
Yii::setAlias('@config', dirname(dirname(__DIR__)) . '/config');
$config = require(APP_PATH . '/../config/web.php');
Ví dụ mã Cest
<?php
namespace tests\api;
use backend\models\user\EduOcrTourist;
use backend\models\user\EduOcrUser;
use backend\modules\user\services\UserEntity;
use config\UserCacheKey;
use psservice\models\user\WxEduUser;
use tests\ApiTester;
class UserControllerCest
{
private $token;
public function _before(ApiTester $I)
{
}
/**
* Đăng nhập người dùng
* @param ApiTester $I
*/
public function actionLoginTest(ApiTester $I)
{
$mobile = '18510473853';
$token = $I->amUserLogin($mobile);
$I->sendCommandToRedis('select', getPsYaconfEnv('PS_OCR_SINGLE_REDIS_DATABASE_1'));
$userRedisInfo = $I->grabFromRedis(sprintf(UserCacheKey::USER_INFO, $token));
$userRedisInfo = json_decode($userRedisInfo, 1);
codecept_debug($userRedisInfo);
$I->assertGreaterThan(0, $userRedisInfo['userId']);
$I->assertEquals(0, $userRedisInfo['touristUserId']);
$I->assertEquals(UserEntity::$roleMap['user'], $userRedisInfo['role']);
$I->assertEquals($mobile, $userRedisInfo['mobile']);
$I->assertLessOrEquals(10, (time() - strtotime($userRedisInfo['loginTime'])));
$I->seeRecord(WxEduUser::className(), ['UserId' => $userRedisInfo['commonUserId']]);
}
/**
* Đăng nhập khách
* @param ApiTester $I
*/
public function actionTouristLoginTest(ApiTester $I)
{
$token = $I->amTouristLogin('6CB7B05E-DE62-415A-96CF-6D57B666F939');
$I->sendCommandToRedis('select', getPsYaconfEnv('PS_OCR_SINGLE_REDIS_DATABASE_1'));
$userRedisInfo = $I->grabFromRedis(sprintf(UserCacheKey::USER_INFO, $token));
$userRedisInfo = json_decode($userRedisInfo, 1);
codecept_debug($userRedisInfo);
$I->assertGreaterThan(0, $userRedisInfo['id']);
$I->seeRecord(EduOcrTourist::className(), ['deviceId' => '6CB7B05E-DE62-415A-96CF-6D57B666F939']);
}
/**
* Đăng xuất
* @param ApiTester $I
*/
public function actionLogoutTest(ApiTester $I)
{
$this->token = $I->amUserLogin('18510473853');
$I->sendPOST('/user/user/logout', [
'token' => $this->token,
'deviceId' => '6CB7B05E-DE62-415A-96CF-6D57B666F939',
]);
$I->seeResponseContainsJson(['code' => 99999]);
}
/**
* Thông tin người dùng đăng nhập
*/
public function actionInfoTest(ApiTester $I)
{
$mobile = '18510473853';
$this->token = $I->amUserLogin($mobile);
$I->sendGET('/user/user/info', [
'token' => $this->token,
]);
$ret = json_decode($I->grabResponse(), 1);
$I->seeRecord(EduOcrUser::className(), ['id' => $ret['data']['userId'], 'mobile' => $mobile]);
}
}
Thêm phương thức tùy chỉnh
Tạo file tests/_support/Helper/{suite_name}.php và thêm phương thức. Sau đó, bạn có thể gọi chúng thông qua đối tượng $I của ApiTester.
Chạy mã kiểm thử và tạo báo cáo độ bao phủ
php codecept.phar run -coverage --coverage-html --coverage-xml
Báo cáo sẽ được tạo trong thư mục tests/_output/coverage/.
Bạn có thể xem báo cáo bằng cách cài đặt máy chủ tĩnh nginx.
Sử dụng mã kiểm thử để tái cấu trúc Các bước:
- Viết mã kiểm thử
- Duy trì và cải thiện độ bao phủ của mã kiểm thử
- Chạy mã kiểm thử và đảm bảo nó thông qua. Lặp lại các bước 1, 2, 3
- Khi mã nguồn trở nên phức tạp
- Tái cấu trúc
- Hợp nhất các vòng lặp, phương thức, lớp tương tự
- Trích xuất phương thức
- v.v.
- Chạy mã kiểm thử, tìm các trường hợp thất bại
- Sửa mã tái cấu trúc, đảm bảo nó thông qua các trường hợp kiểm thử. Lặp lại các bước 5, 6, 7
Sử dụng mã kiểm thử để nhanh chóng hiểu mã mới
steps sẽ in ra các khẳng định đang được thực thi, giúp quan sát hành vi của mã kiểm thử và cách sử dụng API.
php codecept.phar run api --steps # In ra các bước thực thi