在我们开发的时候,测试是必不可少的东西,那么有个好的测试工具才能让你测试的效率提升,现在就介绍下最近我发现的单元测试工具-phpunit吧.
phpunit
phpunit是php 轻量级的单元测试框架,只需要编写好单元测试代码,运行即可测试结果是否和预期结果一样,如果不一样则会报错.
官方中文文档:http://www.phpunit.cn/manual/current/zh_cn/installation.html
请根据官方文档的安装方法进行安装.
本人使用的是composer安装方式:
代码语言:javascript复制 composer require --dev phpunit/phpunit ^7.5
编写测试用例
api接口测试
为了方便发起http请求,本文还额外引入了curl组件:
代码语言:javascript复制composer require php-curl-class/php-curl-class
假设我们需要测试/Index/index接口,正确调用后,接口会输出"hello world":
代码语言:javascript复制<?php
/**
* Created by PhpStorm.
* User: Tioncico
* Date: 2019/4/2 0002
* Time: 10:24
*/
namespace ApiTestIndex;
use AppHttpControllerIndex;
use CurlCurl;
use PHPUnitFrameworkTestCase;
class IndexTest extends TestCase
{
public function testIndex()
{
$url = '127.0.0.1:9501/Index/index';//api地址
$curl = new Curl();
$data = [//get数据
'adminAccount' => 'testncl',
'adminName' => '宁成龙',
'adminPassword' => '123456',
];
$curl->setCookies([//设置cookie
'cookieName' => 1,
]);
$curl->get($url, $data);
if ($curl->response) {
var_dump($curl->response);
} else {
echo 'Error: ' . $curl->errorCode . ': ' . $curl->errorMessage . "n";
}
$this->assertTrue(!!$curl->response);//断言结果是否为true,如果不为true则报错
$this->assertEquals('hello world', $curl->response);//断言结果是否等于hello world,如果不等于则报错
}
}
php运行单元测试
代码语言:javascript复制php vendor/phpunit/phpunit/phpunit ./ApiTest/Index/IndexTest.php//后面的是你写的单元测试例子的路径
类方法测试
假设我们写了一个类:
代码语言:javascript复制<?php
/**
* Created by PhpStorm.
* User: Tioncico
* Date: 2019/4/2 0002
* Time: 10:51
*/
class User
{
function add($data){
if (empty($data)){
return false;
}
return $data;
}
function get($id){
return [
'id'=>1,
'name'=>'test'
];
}
function delete($id){
return true;
}
}
编写测试用例
代码语言:javascript复制<?php
/**
* Created by PhpStorm.
* User: Tioncico
* Date: 2019/4/2 0002
* Time: 10:53
*/
use PHPUnitFrameworkTestCase;
include "User.php";//引入User类,可使用自动加载省略这步
class UserTest extends TestCase
{
public function testGet()
{
$user = new User();
$data= $user->get(1);
$this->assertEquals('1',$data['id']);//断言返回的id为1
}
public function testAdd()
{
$user = new User();
$data = [
'id'=>1,
'name'=>'tioncico'
];
$this->assertEquals($data,$user->add($data));//断言传入data返回data
$this->assertFalse($user->add([]));//断言传入空数组返回false
}
public function testDelete()
{
$user = new User();
$data= $user->delete(1);
$this->assertTrue($data);//断言返回true
}
}
断言
在上面的例子中,我们知道了断言
断言是编程术语,表示为一些布尔表达式,程序员相信在程序中的某个特定点该表达式值为真
例如上面的api接口,当正确调用时一定会输出"hello world",断言它将会输出hello world,如果没有输出该结果则代表断言出错
在phpunit中,还有其他的断言方法,例如:
布尔类型
方法名 | 含义 | 参数 | 返回值 |
---|---|---|---|
assertTrue | 断言为真 | | |
assertFalse | 断言为假 | | |
NULL类型
方法名 | 含义 | 参数 | 返回值 |
---|---|---|---|
assertNull | 断言为NULL | | |
assertNotNull | 断言非NULL | | |
数字类型
方法名 | 含义 | 参数 | 返回值 |
---|---|---|---|
assertEquals | 断言等于 | | |
assertNotEquals | 断言不等于 | | |
assertGreaterThan | 断言大于 | | |
assertGreaterThanOrEqual | 断言大于等于 | | |
assertLessThan | 断言小于 | | |
assertLessThanOrEqual | 断言小于等于 | | |
字符类型
方法名 | 含义 | 参数 | 返回值 |
---|---|---|---|
assertEquals | 断言等于 | | |
assertNotEquals | 断言不等于 | | |
assertContains | 断言包含 | | |
assertNotContains | 断言不包含 | | |
assertContainsOnly | 断言小于 | | |
assertLessThanOrEqual | 断言只包含 | | |
assertNotContainsOnly | 断言不只包含 | | |
数组类型
方法名 | 含义 | 参数 | 返回值 |
---|---|---|---|
assertEquals | 断言等于 | | |
assertNotEquals | 断言不等于 | | |
assertArrayHasKey | 断言有键 | | |
assertArrayNotHasKey | 断言没有键 | | |
assertContains | 断言包含 | | |
assertNotContains | 断言不包含 | | |
assertContainsOnly | 断言只包含 | | |
assertNotContainsOnly | 断言不只包含 | | |
对象类型
方法名 | 含义 | 参数 | 返回值 |
---|---|---|---|
assertAttributeContains | 断言属性包含 | | |
assertAttributeContainsOnly | 断言属性只包含 | | |
assertAttributeEquals | 断言属性等于 | | |
assertAttributeGreaterThan | 断言属性大于 | | |
assertAttributeGreaterThanOrEqual | 断言属性大于等于 | | |
assertAttributeLessThan | 断言属性小于 | | |
assertAttributeLessThanOrEqual | 断言属性小于等于 | | |
assertAttributeNotContains | 断言不包含 | | |
assertAttributeNotContainsOnly | 断言属性不只包含 | | |
assertAttributeNotEquals | 断言属性不等于 | | |
assertAttributeNotSame | 断言属性不相同 | | |
assertAttributeSame | 断言属性相同 | | |
assertSame | 断言类型和值都相同 | | |
assertNotSame | 断言类型或值不相同 | | |
assertObjectHasAttribute | 断言对象有某属性 | | |
assertObjectNotHasAttribute | 断言对象没有某属性 | | |
class类型
方法名 | 含义 | 参数 | 返回值 |
---|---|---|---|
assertClassHasAttribute | 断言类有某属性 | | |
assertClassHasStaticAttribute | 断言类有某静态属性 | | |
assertClassNotHasAttribute | 断言类没有某属性 | | |
assertClassNotHasStaticAttribute | 断言类没有某静态属性 | | |
文件相关
方法名 | 含义 | 参数 | 返回值 |
---|---|---|---|
assertFileEquals | 断言文件内容等于 | | |
assertFileExists | 断言文件存在 | | |
assertFileNotEquals | 断言文件内容不等于 | | |
assertFileNotExists | 断言文件不存在 | | |
XML相关
方法名 | 含义 | 参数 | 返回值 |
---|---|---|---|
assertXmlFileEqualsXmlFile | 断言XML文件内容相等 | | |
assertXmlFileNotEqualsXmlFile | 断言XML文件内容不相等 | | |
assertXmlStringEqualsXmlFile | 断言XML字符串等于XML文件内容 | | |
assertXmlStringEqualsXmlString | 断言XML字符串相等 | | |
assertXmlStringNotEqualsXmlFile | 断言XML字符串不等于XML文件内容 | | |
assertXmlStringNotEqualsXmlString | 断言XML字符串不相等 | | |
也可以通过查看vendorphpunitphpunitsrcFrameworkAssert.php 文件实现的所有方法
基镜
在编写测试时,最费时的部分之一是编写代码来将整个场景设置成某个已知的状态,并在测试结束后将其复原到初始状态。这个已知的状态称为测试的 基境(fixture)。
例如在User测试中,我们每次都需要new User进行测试user类,其实我们完全可以使用基镜:
代码语言:javascript复制<?php
/**
* Created by PhpStorm.
* User: Tioncico
* Date: 2019/4/2 0002
* Time: 10:53
*/
use PHPUnitFrameworkTestCase;
include "User.php";//引入User类,可使用自动加载省略这步
class UserTest extends TestCase
{
protected $user;
function setUp()
{
parent::setUp(); // TODO: Change the autogenerated stub
$this->user = new User();
//例如这个类有很多属性需要自定义,初始化,都可以在这里完成
//例如这个类需要查找数据库进行赋值,都可以在这里完成
//例如需要新增一条数据用于测试,都可以在这里完成
}
function tearDown()
{
parent::tearDown(); // TODO: Change the autogenerated stub
unset($this->user);//销毁类属性,都可以在这里调用
//例如测试完需要把数据还原回之前的状态,可以在这里完成
//例如测试完需要把数据删除,可以在这里完成
}
public function testGet()
{
$user = $this->user;
$data= $user->get(1);
$this->assertEquals('1',$data['id']);//断言返回的id为1
}
public function testAdd()
{
$user = $this->user;
$data = [
'id'=>1,
'name'=>'tioncico'
];
$this->assertEquals($data,$user->add($data));//断言传入data返回data
$this->assertFalse($user->add([]));//断言传入空数组返回false
}
public function testDelete()
{
$user = $this->user;
$data= $user->delete(1);
$this->assertTrue($data);//断言返回true
}
}
继承
phpunit的测试用例都可以直接继承,进行多继承测试
例如我们需要编写/Admin/Index/index /Admin/User/index.....等等,位于Admin模块下的所有控制器,我们可以先编写一个admin测试基类:
代码语言:javascript复制<?php
/**
* Created by PhpStorm.
* User: Tioncico
* Date: 2019/4/2 0002
* Time: 11:10
*/
use PHPUnitFrameworkTestCase;
class AdminBase extends TestCase
{
protected $session;//测试admin模块的控制器时,都是需要登录的,每次请求接口都需要一个登陆标识
function setUp()
{
parent::setUp(); // TODO: Change the autogenerated stub
$this->login();
}
function tearDown()
{
parent::tearDown(); // TODO: Change the autogenerated stub
$this->logout();
}
/**
* 登陆逻辑
* login
* @author Tioncico
* Time: 11:11
*/
function login(){
//这里需要调用后台的登陆接口,进行登陆,并把session赋值到$this->session
$this->session='测试session';
}
/**
* 退出逻辑
* logout
* @author Tioncico
* Time: 11:11
*/
function logout(){
//这里需要通过$this->session去调用退出接口,这样就退出了一次测试
}
}
这样,我们所有关于admin模块的测试用例,都可以继承该类进行测试,每次测试时,都会调用该基类的登陆进行登陆,并将session赋值,我们只需要直接$this->session取出即可调用测试
额外的方法
在这里需要注意的是:
只有类名为xxTest和方法名为testxx的才是测试例子,在有的时候,我们可以写更多的方法用于给测试方法调用,而在运行测试用例的时候并不会调用到该方法,例如上面的adminBase 的login logout方法,直接运行测试的时候不会直接被调用.
多参数测试(数据供给器)
我们可以通过在注释增加数据供给器方法名,进行给测试用例增加参数测试,例如我们需要测试User类的add方法:
代码语言:javascript复制<?php
/**
* Created by PhpStorm.
* User: Tioncico
* Date: 2019/4/2 0002
* Time: 10:51
*/
class User
{
function add($data){
if ($data['id']<=0){
return false;
}
if (strlen($data['name'])<=5){
return false;
}
if ($data['age']>190||$data['age']<10){
return false;
}
return $data;
}
}
测试用例:
代码语言:javascript复制<?php
/**
* Created by PhpStorm.
* User: Tioncico
* Date: 2019/4/2 0002
* Time: 10:53
*/
use PHPUnitFrameworkTestCase;
include "User.php";//引入User类,可使用自动加载省略这步
class UserTest extends TestCase
{
protected $user;
function setUp()
{
parent::setUp(); // TODO: Change the autogenerated stub
$this->user = new User();
//例如这个类有很多属性需要自定义,初始化,都可以在这里完成
//例如这个类需要查找数据库进行赋值,都可以在这里完成
//例如需要新增一条数据用于测试,都可以在这里完成
}
function tearDown()
{
parent::tearDown(); // TODO: Change the autogenerated stub
unset($this->user);//销毁类属性,都可以在这里调用
//例如测试完需要把数据还原回之前的状态,可以在这里完成
//例如测试完需要把数据删除,可以在这里完成
}
/**
* @dataProvider addData
* testAdd
* @param $id
* @param $name
* @param $age
* @author Tioncico
* Time: 11:20
*/
public function testAdd($id,$name,$age)
{
$user = $this->user;
$data = [
'id'=>$id,
'name'=>$name,
'age'=>$age,
];
$this->assertFalse($user->add($data));//断言传入以上所有参数都返回false
}
function addData(){
return [
[0, 'name123', 18],//id不能为0
[-1, 'name123', 18],//id不能小于0
[99, 'name', 18],//name长度不够
[1, '', 18],//name为空
[1, null, 18],//name为null
[1, 'name123', 500],//年龄太大
];
}
}
这样既可一次性测试多种错误判断的情况
详细的数据供给器可查看:phpunit数据供给器
phpstorm使用phpunit测试
只需要根据图示,点击 号,然后根据安装的方式(composer,phar等)进行配置既可
新增测试用例:
运行测试用例:
测试结果大概如下:
当你的项目有改动的时候,都可以直接运行测试用例,来测试你的改动是否影响了其他地方,非常方便
本文为仙士可原创文章,转载无需和我联系,但请注明来自仙士可博客www.php20.cn
- 上一篇: 钞票找零-贪心,动态规划算法
- 下一篇: 关于本人对学习知识的方法的理解