专栏首页仙士可博客phpunit-单元测试神器

phpunit-单元测试神器

在我们开发的时候,测试是必不可少的东西,那么有个好的测试工具才能让你测试的效率提升,现在就介绍下最近我发现的单元测试工具-phpunit吧.

phpunit

phpunit是php 轻量级的单元测试框架,只需要编写好单元测试代码,运行即可测试结果是否和预期结果一样,如果不一样则会报错.

官方中文文档:http://www.phpunit.cn/manual/current/zh_cn/installation.html

请根据官方文档的安装方法进行安装.

本人使用的是composer安装方式:

 composer require --dev phpunit/phpunit ^7.5

编写测试用例

api接口测试

为了方便发起http请求,本文还额外引入了curl组件:

composer require php-curl-class/php-curl-class

假设我们需要测试/Index/index接口,正确调用后,接口会输出"hello world":

<?php
/**
 * Created by PhpStorm.
 * User: Tioncico
 * Date: 2019/4/2 0002
 * Time: 10:24
 */

namespace ApiTest\Index;

use App\HttpController\Index;
use Curl\Curl;
use PHPUnit\Framework\TestCase;

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运行单元测试

php vendor/phpunit/phpunit/phpunit ./ApiTest/Index/IndexTest.php//后面的是你写的单元测试例子的路径

类方法测试

假设我们写了一个类:

<?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;
    }
}

编写测试用例

<?php
/**
 * Created by PhpStorm.
 * User: Tioncico
 * Date: 2019/4/2 0002
 * Time: 10:53
 */

use PHPUnit\Framework\TestCase;

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字符串不相等

也可以通过查看vendor\phpunit\phpunit\src\Framework\Assert.php 文件实现的所有方法

基镜

在编写测试时,最费时的部分之一是编写代码来将整个场景设置成某个已知的状态,并在测试结束后将其复原到初始状态。这个已知的状态称为测试的 基境(fixture)。

例如在User测试中,我们每次都需要new User进行测试user类,其实我们完全可以使用基镜:

<?php
/**
 * Created by PhpStorm.
 * User: Tioncico
 * Date: 2019/4/2 0002
 * Time: 10:53
 */

use PHPUnit\Framework\TestCase;

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测试基类:

<?php
/**
 * Created by PhpStorm.
 * User: Tioncico
 * Date: 2019/4/2 0002
 * Time: 11:10
 */

use PHPUnit\Framework\TestCase;

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方法:

<?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;
    }
}

测试用例:

<?php
/**
 * Created by PhpStorm.
 * User: Tioncico
 * Date: 2019/4/2 0002
 * Time: 10:53
 */

use PHPUnit\Framework\TestCase;

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • easyswoole实现模板渲染

    easyswoole框架使用模板直接使用模板引擎,是会有问题的,所以增加了渲染驱动

    仙士可
  • ajaxfileupload上传文件和报错syntaxerror: Unexpected end of input(…)

    jQuery插件AjaxFileUpload可以实现ajax文件上传,下载地址:http://www.phpletter.com/contents/ajaxfi...

    仙士可
  • mysql统计函数

    本文为仙士可原创文章,转载无需和我联系,但请注明来自仙士可博客www.php20.cn

    仙士可
  • soapUI 接口测试断言

    断言的功能不言而喻, 是指定的restful api是否正常,判断它的响应值是否符合预期标准.

    louiezhou001
  • Jmeter(二十一) - 从入门到精通 - JMeter断言 - 上篇(详解教程)

      最近由于宏哥在搭建自己的个人博客可能更新的有点慢。断言组件用来对服务器的响应数据做验证,常用的断言是响应断言,其支持正则表达式。虽然我们的通过响应断言能够完...

    北京-宏哥
  • Jmeter系列(18)- 断言Assertions 的入门介绍

    https://www.cnblogs.com/poloyy/category/1746599.html

    小菠萝测试笔记
  • JMeter专题系列(五)检查点

    检查点:我们对用户名和密码进行了参数化,那么怎样来判断jmeter有没有正确调用t.dat里面的文件呢。当然,我们可以从结果图表中查看。但我还是想在“登录”这个...

    流柯
  • TestNg中的断言你真的了解吗

    在执行自动化测试脚本的时候,我们需要自动判断测试脚本执行完成后的实际结果是否与预期结果一致,这个时候就需要在程序运行之前写入断言,判断当前程序执行后是否正常。

    软件测试君
  • 走进Java接口测试之流式断言库AssertJ

    在设计自动化接口 Cases 时,遵守的核心原则是3A(Arrange-> Actor ->Assert)原则;

    高楼Zee
  • Jmeter(二十二) - 从入门到精通 - JMeter

    断言组件用来对服务器的响应数据做验证,常用的断言是响应断言,其支持正则表达式。虽然我们的通过响应断言能够完成绝大多数的结果验证工作,但是JMeter还是为我们提...

    北京-宏哥

扫码关注云+社区

领取腾讯云代金券