PHPUnit安装

1. composer require --dev phpunit/phpunit

执行这个命令之后可检查两处:

  • composer.json 文件中增加了如下的依赖,并且composer自动加载的相关文件都更新了

    1. {
    2. "require-dev": {
    3. "phpunit/phpunit": "^7.0"
    4. }
    5. }
  • vendor 目录中增加了 phpunit/phpunit 相关的文件夹

2. 利用composer的自动加载机制,引入测试代码在项目中的加载

  1. {
  2. "autoload": {
  3. "psr-4": {
  4. "Tests\\": "tests/"
  5. }
  6. }
  7. }

3. 配置PHPStorm

如下图:Settings > Languages & Frameworks > PHP > Test Frameworks
确保单元测试框架加载了本项目的 vendor/autoload.php 文件

image.png

快速上手

1. 在 tests 文件夹新增 ExampleTest.php 文件,内容如下

  1. <?php
  2. namespace tests;
  3. class ExampleTest extends \PHPUnit\Framework\TestCase
  4. {
  5. public function testBasicTest()
  6. {
  7. $this->assertTrue(true);
  8. }
  9. }

2. 快速运行当前测试文件的快捷键是 Ctrl + Shift + F10

如果这组快捷键在你的IDE无效,亦可点击要测试的方法名字,右键 选中 执行 Run 'testBasicTest' 操作

2019-07-24 11-23-58屏幕截图_meitu_1.jpg

3. 对的,就是如此简单!

按照第二步的操作我们可以看到IDE底部会输出单元测试的结果日志,特别的,你看到了ok 就代表我们的测试通过了。

2019-07-24 11-37-15屏幕截图_meitu_2.jpg

单元测试到底能干啥?

本篇的重点不是来宣讲单元测试的重要性的问题,因为这个答案是肯定的是毋容置疑的,如果非要提这个问题:
1、编写测试用例,帮助我们更好的梳理业务代码的组织形式,比如我们和前端预定了字段和返回形式,就可以根据接口定义断言我们的返回,提高系统健壮性;
2、利用单元测试定义检验系统单一代码块是否符合预期,方便以后能够放心大胆的做重构,只要我们的用例能够通过;
3、测试覆盖率是衡量软件质量的重要标准之一;
4、为落地DevOps打基础,代码交付速度提升也增加了代码风险,利用单元测试在持续集成阶段就能自动检验是否有代码bug影响旧逻辑,方便更快更好的交付软件;

除此之外,不再过多照本宣科的讲解单元测试相关,我们把重点还是放在如何落地到项目中。

系统引入单元测试

比如我想测试 sdk 下一系列 Service 文件,我在 tests 目录下创建了一个 services 目录,然后新增一个 H5payTest.php 文件,如你所见,单元测试的文件名后缀要以Test结尾

<?php

namespace tests\services;


class H5payTest extends \PHPUnit\Framework\TestCase
{

}

我们先写一部分代码把要测试逻辑放进去

<?php

namespace tests\services;

use sdk\services\H5payService;

class H5payTest extends \PHPUnit\Framework\TestCase
{
    private $service;

    public function testWx()
    {
        // 我先尝试把我需要测试的类引进来,然后运行
        $this->service = new H5payService();
        $this->assertNotEmpty(1);
    }

}


运行结果

image.png

Error : Class 'sdk\services\H5payService' not found,咦?我需要的类找不到?加载不进来怎么办?这个主要是因为我们的sdk的类文件都依赖 sdk/Autoload.php 这个文件去查找的。但是在这里测试怎么能 require 进来?
PHPStorm也提供了配置的方法,就是运行单元测试前要执行启动脚本,我们新增文件 tests/bootstrap.php
文件内容参考如下

<?php

date_default_timezone_set('Asia/Shanghai');
define("SDK_PATH", __DIR__ . '/../sdk/');
define("CONFIG_PATH", __DIR__ . '/../config/');
define('CONFIG_FILE', __DIR__ . '/../config_map/your-config.php');
define('PJNAME', __DIR__ . 'yourname');
require_once SDK_PATH . 'Autoload.php';

然后把路径在下面的配置中选中

image.png

然后 Ctrl + Shift + F10 运行

image.png

这下就可以了,示例的代码如下,每个待测试的方法 test 开头

<?php

namespace tests\services;

use sdk\services\H5payService;

class H5payTest extends \PHPUnit\Framework\TestCase
{
    private $service;

    public function __construct()
    {
        parent::__construct();
        $this->service = new H5payService();
    }


    public function testWx()
    {
        $params = [
            'agent_id' => 11111103,
            'merchant_id' => 'C555555550670592',
            'pay_type' => 'WX',
            'order_id' => '11111111' . rand(11111, 99999),
            'price' => '1',
            'body' => 'h5支付',
            'client_ip' => '127.0.0.1',
            'open_id' => 'ohTKdw6446494946464yKyR5s',
            'sub_appid' => 'wx136161316494946fa59'
        ];
        $result = $this->service->deal($params);
        $this->assertIsArray($result);
        $this->assertArrayHasKey('open_id', $result);
        $this->assertArrayHasKey('jsapi', $result);
        $this->assertArrayHasKey('plat_orderid', $result);
        $this->assertNotEmpty($result['open_id']);
        $this->assertNotEmpty($result['jsapi']);
        $this->assertNotEmpty($result['plat_orderid']);
    }

    public function testZfb()
    {
        $params = [
            'agent_id' => 1011113,
            'merchant_id' => 'C96669959669666695592',
            'pay_type' => 'ZFB',
            'order_id' => '11111111' . rand(11111, 99999),
            'price' => '1',
            'open_id' => '2343243434',
            'body' => 'h5支付',
            'client_ip' => '127.0.0.1',
        ];
        $result = $this->service->deal($params);
        $this->assertIsArray($result);
    }
}

如何组织用例

一般一个功能集分在一个文件,多个测试方法分别测试不同的代码块,单元测试的关键就是利用”断言” assrrt系列方法判断返回结果是否符合预期。PHPUnit还有一些相对好用的方法帮我们组织数据,在官方文档简单明了。

1 项目根目录新增文件 phpunit.xml

<phpunit bootstrap="src/your-project-boot-file.php">
  <testsuites>
    <testsuite name="money">
      <directory>tests</directory>
    </testsuite>
  </testsuites>
</phpunit>

2 在项目根目录执行 phpunit

它将在递归遍历 tests 时添加所有在 Test.php 文件中找到的 Test 类

3 测试报告

https://phpunit.de/manual/6.5/zh_cn/logging.html

参考