最近公司需要写单元测试,于是便研究了一下单元测试,单元测试很简单。我们的单元测试是和yaf 框架结合的,其实和框架结合,就是在TestCase.php 基类里面对当前框架实例化即可。下面是具体代码
文档地址:https://phpunit.readthedocs.io/zh_CN/latest/index.html
1 获取phpunit
1) 直接下载想对应的版本,目前公司使用的php版本是php7.2 所以直接下载支持php 7.2 对应的phpunit
wget https://phar.phpunit.de/phpunit-8.5.3.phar
$ chmod +x phpunit-8.5.3phar
$ sudo mv phpunit-8.5.3.phar /usr/local/bin/phpunit
2)composer
composer require --dev phpunit/phpunit ^|version|
只要在项目的 composer.json 文件中简单地加上对 phpunit/phpunit 的依赖关系即可
2 phpunit test 目录结构(yaf 目录) 放在当前目录的根目录下即可
tests //按照yaf的目录结构来设计的目录结构,可以根据实际情况,自己来设计
application
controllers
restaurant
AddRestTest.php //具体测试用例
xxxTest.php
yyyTest.php
library
ControllerTestCase.php(继承于TestCase 的controller 基类)
ModelTestCase.php (model 层基类)
TestCase.php(测试的基类)
bootstrap.php(启动文件)
phpunit.xml (配置文件)
3 bootstrap.php 启动文件,不同于yaf 的 Bootstrap.php。tests 里面的bootstrap.php 就是单独的配置文件
<?php /** * In Bootstrap Class, all method with suffix _init will be called by Yaf, * All these method receive a common parameter : Yaf_Dispatcher $dispatcher * And the Calling order same as statement order. * @author carl@chope.co */ //项目 路径 define("APPDIR", realpath(dirname(__FILE__) . '/../')); //ODP 路径 用来获取odp 下面的配置 define('ROOT_PATH', dirname(dirname(dirname(__FILE__))) . '/../'); //当前环境变量 defined('ENVIRONMENT') || define ('ENVIRONMENT', 'TEST-BJ');
4 phpunit.xml 配置文件
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" colors="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/8.5/phpunit.xsd" bootstrap="./bootstrap.php" > <testsuites> <testsuite name="controller"> <directory>./application/controllers/restaurant/</directory> </testsuite> <testsuite name="models"> <directory>./application/models/*Test.php</directory> </testsuite> </testsuites> <logging> <log type="coverage-html" target="/tmp/report" lowUpperBound="35" highLowerBound="70"/> <log type="coverage-clover" target="/tmp/coverage.xml"/> <log type="coverage-php" target="/tmp/coverage.serialized"/> <log type="coverage-text" target="php://stdout" showUncoveredFiles="false"/> <log type="testdox-html" target="/tmp/testdox.html"/> <log type="testdox-text" target="/tmp/testdox.txt"/> </logging> </phpunit>
1)根据自己的项目路径,来设置test目录
<directory>./application/controllers/restaurant/</directory>
restaurant 目录下的所有*Test.php 的文件都会执行
用当前配置执行的时候会报 Error: Incorrect whitelist config, no code coverage will be generated.
这是因为没有加上过滤白名单 ,只需要在 <logging> 上面加上
1 2 3 4 5
<filter> <whitelist> <directory suffix=".php">application/</directory> </whitelist> </filter>
application 为当前的测试目录 。
白名单设置也可以设置成具体的某个文件
4 TestCase.php
<?php /** * phpunit 基类 */ namespace tests\library; use PHPUnit\Framework\TestCase as Test; class TestCase extends Test{ protected static $_application = null; public function setUp(): void{ self::$_application = $this->getApplication(); parent::setUp(); } public function getApplication(){ if (self::$_application == null) { $this->setApplication(); } return self::$_application; } //当前环境不支持yaf命名空间,所以无法再次直接使用 public function setApplication(){ $myproject_config = array( "application" => array( "directory" => APPDIR, ), ); $application = new \Yaf_Application($belly_config); self::$_application = $application->bootstrap(); } }
1) 设置phpunit 测试的基类 为了避免冲突设置命名空间。
2)一般的server环境的php.ini 里面关于yaf 的命名空间默认是不启用的,如果启用了yaf 的命名空间,那么程序中在使用yfa框架的时候必须用命名空间的调用方式来调用yfa 方法。
3)因为本页面定义了命名空间,如果环境里面没有开启命名空间,那么在加载yfa 对象的时候 必须使用加载全局类的方式 new \Yaf_Application($myproject
_config);
5 ControllerTestCase.php(测试实例的基类,用来初始化当前controller 测试的内容)
<?php namespace tests\library; require_once APPDIR . '/tests/library/TestCase.php'; /** * 控制器测试基类 */ class ControllerTestCase extends TestCase { public static $user_pass; public static $url; public static function initEnv(){ $config_arr = \Core_Conf::getConf('odp_myproject/' . ENVIRONMENT); self::$user_pass = $config_arr['odp_myproject']['commerceapi_username'] . ':' . $config_arr['odp_belly']['commerceapi_password']; self::$url = $config_arr['odp_belly']['belly_endpoint']; } }
1)定义命名空间
2)如果没用使用autoload 的话需要自己加载TestCase.php
6 具体测试case
<?php require_once APPDIR . '/tests/library/ControllerTestCase.php'; /** * 首页控制器测试类 * phpunit --bootstrap /var/www/docker/carl/b2c/code/Production_B2C/odp/app/myproject/tests/bootstrap.php /var/www/docker/carl/b2c/code/Production_B2C/odp/app/myproject/tests/application/controllers/restaurant/AddRestTest.php */ class AddRestTest extends \tests\library\ControllerTestCase { /** * 测试添加餐厅info */ public function test_addRestInfo() { $param_arr['RestaurantUID'] = "phpunit_".date('YmdHis'); $param_arr['RestaurantName'] = $param_arr['RestaurantUID'].'_rest'; $param_arr['createTime'] = time(); $param_arr['address_display'] = 'Paya Lebar, Paya Lebar Air Base (QPG), Singapore'; $param_arr['phone_display'] = '123456789'; $param_arr['phone'] = '123456789'; $param_arr['vendor_logo_url'] = 'https://chopetest.s3.cn-north-1.amazonaws.com.cn/uploads/2020/04/1586866214_23086.jpg';//餐厅UID $param_arr['widget_logo_url'] = 'https://chopetest.s3.cn-north-1.amazonaws.com.cn/uploads/2020/04/1586866214_23086.jpg'; $param_arr['restaurant_email'] = '401626772@qq.com'; $param_arr['restaurant_email_to'] = '1401626772@qq.com'; $param_arr['is_mr'] = 2; $param_arr['country_code'] = 'SG'; $res = Service_Restaurant::addRestInfo($param_arr); //判断返回的餐厅info自增ID是否大于0 $this->assertGreaterThan(0, $res,'Add Restaurant Info error'); return $res; } /** * 测试获取餐厅列表 * @depends test_addRestInfo */ public function test_getRestInfo($restaurant_id){ //获取餐厅列表 $restinfo = Service_Restaurant::getRestInfo(array('id'=>$restaurant_id)); $this->assertNotEmpty($restinfo,'Can not get restaurant info'); } public function test_xx(){ echo 1; } }
1) 如果不经过特殊设置,case 里面的函数是按顺序执行的
2)如果一个函数想用另一个函数的返回值,只需要在函数的注释处加上@depends test_addRestInfo(具体的想要使用返回值的函数名字)
3)如果函数里面没有调用任何断言,在执行的时候会报 notice
7 如何调用 phpunit
1) 如果phpunit 以可执行文件的形式 加入到全局目录就可以直接使用 (/usr/local/bin)
2) 如果没有加入全局目录,就需要带上目录名字
3)以下所有的调用都是在phpunit 加入到全局目录里面
方式 1 不需要进入到 tests 目录里面
phpunit --bootstrap /var/www/docker/myproject
/tests/bootstrap.php /var/www/docker/myproject
/tests/application/controllers/restaurant/AddRestTest.php
--bootstrap 制定加载启动文件
/var/www/docker/myproject
/tests/bootstrap.php 启动文件目录
/var/www/docker/myproject
/tests/application/controllers/restaurant/AddRestTest.php 具体的要执行的case
方式2 定义了 phpunit.xml 文件所以 直接进入到 tests 目录
phpunit 后面无需跟任何参数
附言:
1)如果phpunit.xml没有定义 <logging>。。。</logging> 那么 执行结果 会直接在命令行输出
2) 如果phpunit.xml 定义了 <logging>。。。</logging> 那么执行结果会输出成 html,xml,text格式的文件