zoukankan      html  css  js  c++  java
  • Codeception 实战

    Codeception 测试 Php 代码

    一、一句话概述

    使用 cc 进行单元测试,保证现有代码质量,为以后维护与重构提供支撑。

    二、目标

    • 安装配置 cc
    • 编写测试代码,简化开发与最大化稳定性和可维护性

    三、测试的类型

    1. 单元测试(UT)

    • 执行一段与其他代码完全隔离的代码单元
    • 断言代码行为
    • 描述用例的预期

    2. 功能测试(FT)

    • 执行应用(客户端)请求
    • 断言返回值
    • 描述应用预期行为
    • 依赖框架

    3. Web 服务测试

    • 通过 http client 执行 api 请求
    • 对 api 返回值断言
    • 描述 api 行为

    四、系统要求

    • PHP 5.4+
    • json 扩展
    • mbstring 扩展
    • xdebug 扩展(生成覆盖率报告)

    下载安装配置 php扩展 xdebug

    版本选用最新稳定版: 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
    
    在 php.ini 文件中添加此行:
    zend_extension="/wherever/you/put/it/xdebug.so"
    
    查看是否安装上:
    php -i | grep xdebug
    

    五、安装配置与运行 Codeception

    wget http://codeception.com/codecept.phar # 不需要解压
    
    php codecept.phar help # 帮助文档
    php codecept.phar bootstrap # 创建 test & codeception.yml 到当前文件夹
    php codecept.phar build # 通过配置生成必要的类,每次修改配置都需要运行次命令
    
    php codecept.phar run {suite_name} # 不跟 suite name 即是运行全部
    php codecept.phar run api ThingTest.php
    php codecept.phar run api ThingTest.php:method
    

    配置与代码示例

    地址:https://github.com/wdy1184/CodeceptionExampleWithYii2

    六、测试代码格式

    codeception 提供了两种写测试代码的方式

    1. Cept: 一个独立的测试文件。可以写一套测试流程。
    2. Cest: 一个类文件,多个测试写在一个类中。
    3. PHPUnit: 支持 phpunit 原生测试框架的格式

    七、与Yii2集成

    配置:

    image-20190305200555502.png

    _bootstrap.php 代码

    <?php
    
    defined('APP_PATH') or define('APP_PATH', dirname(dirname(__FILE__)));
    // 注册 Composer 自动加载器
    // 包含 Yii 类文件
    
    require(__DIR__ . '/../../psservice/libs/envFun.php');
    require(__DIR__ . '/../../vendor/autoload.php');
    
    // 环境变量配置
    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');
    
    // 暂时向下兼容老文件
    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');
    
    

    Cest 代码示例

    <?php
    namespace testsapi;
    
    use backendmodelsuserEduOcrTourist;
    use backendmodelsuserEduOcrUser;
    use backendmodulesuserservicesUserEntity;
    use configUserCacheKey;
    use psservicemodelsuserWxEduUser;
    use testsApiTester;
    
    class UserControllerCest
    {
        private $token;
    
        public function _before(ApiTester $I)
        {
        }
    
        /**
         * 用户登录
         * @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']]);
        }
    
        /**
         * 游客登录
         * @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::TOURIST_INFO, $token)); // 机缘巧合下,没有使用 touristInfo 常量
            $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']);
        }
    
        /**
         * 登出
         * @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]);
        }
    
        /**
         * 登录用户信息
         */
        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]);
        }
    }
    
    

    八、增加自定义方法

    tests/_support/Helper/{suite_name}.php

    在其中增加方法后,可以通过 ApiTester 的对象 $I 进行调用。

    image-20190305201253542.png

    九、运行测试代码生成测试报告(代码覆盖率)

    php codecept.phar run -coverage --coverage-html --coverage-xml
    

    测试报告会在 tests/_output/coverage/ 中生成。

    通过设定 nginx 静态服务器,可以查看测试报告。如:

    image-20190305204312240.png

    十、利用测试用例进行重构

    步骤:

    1. 编写测试代码
    2. 持续维护测试代码,提高测试代码覆盖率
    3. 运行测试代码使其通过。并不断重复 1、2、3 步骤
    4. 代码库越来越庞杂
    5. 重构
      1. 合并相似循环、方法、类
      2. 提取方法
      3. 等等
    6. 运行测试用例,找到失败的用例
    7. 修改重构后的代码,使其通过测试用例,并重复 5、6、7 步骤

    十一、利用测试用例,快速了解新代码

    steps 会在执行的时候打印出执行的断言,有助于观察测试用例做了什么,以及怎么使用你写的接口。

    即测试用例是 : self-document 的。

    php codecept.phar run api --steps # steps 会在执行的时候打印出执行的断言
    

    image-20190305202846264.png

  • 相关阅读:
    Java 概述
    vue组件事件
    小程序注册
    小程序基础知识梳理
    小程序简介
    公众号
    jeecg-boot
    小程序背景图
    bootstrap-select采坑
    存取cookie
  • 原文地址:https://www.cnblogs.com/wudanyang/p/10647875.html
Copyright © 2011-2022 走看看