本系列教程所有的PHPUnit测试基于PHPUnit6.5.9版本,Lumen 5.5框架

目录结构

模块下的目录是符合Lumen的模块结构的
如:Controllers、Models、Logics等是Lumen模块目录下的结构目录
如果有自己的目录同级分配即可,如我这里的Requests

整体结构

├── BaseCase.php 重写过Lumen基类的测试基类,用于我们用这个基类做测试基类,后续会说明
├── bootstrap.php tests自动加载文件
├── Cases 测试用例目录
│   └── Headline 某测试模块
│       ├── logs 日志输出目录
│       ├── PipeTest.php PHPUnit流程测试用例
│       ├── phpunit.xml phpunit配置文件xml
│       └── README.md 本模块测试用例说明
├── ExampleTest.php 最原始测试demo
└── TestCase.php Lumen自带的测试基类

某模块的目录结构

Headline  //某测试模块测试用例目录
├── Cache
├── Controllers
│   ├── ArticleTest.php
│   ├── ...
├── Listeners
│   └── MyListener.php
├── Logics
├── Models
│   ├── ArticleTest.php
│   ├── ...
├── README.md
├── Requests
│   ├── ArticleTest.php
│   ├── ...
├── logs //日志和覆盖率目录
│   ├── html
│   │   ├── ...
│   │   └── index.html
│   ├── logfile.xml
│   ├── testdox.html
│   └── testdox.txt
├── phpunit-debug-demo.xml   //phpunit.xml案例
├── phpunit-debug.xml        //改名后测试用的
└── phpunit.xml              //正式用的xml配置

BaseCase.php

<?php
namespace Test;use Illuminate\Database\Eloquent\Factory;class BaseCase extends TestCase
{protected $seeder = false;const DOMAIN = "http://xxx.com";const API_URI = [];const TOKEN = ['local' => 'token*','dev' => 'token*','prod' => '' //如果测试真实请填写授权token];/*** 重写setUp*/public function setUp(){parent::setUp();$this->seeder = false;if (method_exists($this, 'factory')) {$this->app->make('db');$this->factory($this->app->make(Factory::class));if (method_exists($this, 'seeder')) {if (!method_exists($this, 'seederRollback')) {dd("请先创建seederRollback回滚方法");}$this->seeder = true;$this->seeder();}}}/*** 重写tearDown*/public function tearDown(){if ($this->seeder && method_exists($this, 'seederRollback')) {$this->seederRollback();}parent::tearDown();}/*** 获取地址* @param string $apiKey* @param string $token* @return string*/protected function getRequestUri($apiKey = 'list', $token = 'dev', $ddinfoQuery = true){$query = "?token=" . static::TOKEN[strtolower($token)];if ($ddinfoQuery) {$query = $query . "&" . http_build_query(static::DDINFO);}return $apiUri = static::DOMAIN . static::API_URI[$apiKey] . $query;}
}

phpunit-debug-demo.xml

本文件是我们单独为某些正在测试的测试用例,直接编写的xml,可以不用来回测试,已经测试成功的测试用例了,最后全部编写完测试用例,再用正式phpunit.xml即可,具体在运行测试阶段看如何指定配置

<?xml version="1.0" encoding="UTF-8"?><phpunitbootstrap="../../bootstrap.php"convertErrorsToExceptions="true"convertNoticesToExceptions="false"convertWarningsToExceptions="false"colors="true"><filter><whitelist processuncoveredfilesfromwhitelist="true"><directory suffix=".php">../../../app/Http/Controllers/Headline</directory><directory suffix=".php">../../../app/Http/Requests/Headline</directory><directory suffix=".php">../../../app/Models/Headline</directory><exclude><file>../../../app/Models/Headline/ArticleKeywordsRelationModel.php</file></exclude></whitelist></filter><testsuites><testsuite name="Headline Test Suite"><directory>./</directory></testsuite></testsuites><php><ini name="date.timezone" value="PRC"/><env name="APP_ENV" value="DEV"/></php><logging><log type="coverage-html" target="logs/html/" lowUpperBound="35"highLowerBound="70"/><log type="json" target="logs/logfile.json"/><log type="tap" target="logs/logfile.tap"/><log type="junit" target="logs/logfile.xml" logIncompleteSkipped="false"/><log type="testdox-html" target="logs/testdox.html"/><log type="testdox-text" target="logs/testdox.txt"/></logging><listeners><!--<listener class="\Test\Cases\Headline\Listeners\MyListener" file="./Listeners/MyListener.php">--><!--<arguments>--><!--<array>--><!--<element key="0">--><!--<string>Sebastian</string>--><!--</element>--><!--</array>--><!--<integer>22</integer>--><!--<string>April</string>--><!--<double>19.78</double>--><!--<null/>--><!--<object class="stdClass"/>--><!--</arguments>--><!--</listener>--><!--<listener class="\Test\Cases\Headline\Listeners\MyListener" file="./Listeners/MyListener.php">--><!--<arguments>--><!--<array>--><!--<element key="0">--><!--<string>Sebastian</string>--><!--</element>--><!--</array>--><!--<integer>22</integer>--><!--</arguments>--><!--</listener>--></listeners>
</phpunit>

测试用例案例

<?php
/*** Created by PhpStorm.* User: qikailin* Date: 2019-01-29* Time: 11:57*/namespace Test\Cases\Headline\Articles;use App\Http\Controllers\Headline\ArticleController;
use App\Models\Headline\ArticleCategoryRelationModel;
use App\Models\Headline\ArticleContentModel;
use App\Models\Headline\ArticleKeywordsRelationModel;
use App\Models\Headline\ArticlesModel;
use Faker\Generator;
use Illuminate\Http\Request;
use Test\BaseCase;class ArticleTest extends BaseCase
{private static $model;public static function setUpBeforeClass(){parent::setUpBeforeClass();self::$model = new ArticlesModel();}/*** 生成factory faker 数据构建模型对象* @codeCoverageIgnore*/public function factory($factory){$words = ["测试", "文章", "模糊", "搜索"];$id = 262;$factory->define(ArticlesModel::class, function (Generator $faker) use (&$id, $words) {$id++;return ['id' => $id,'uri' => $faker->lexify('T???????????????????'),'title' => $id == 263 ? "搜索" : $words[rand(0, sizeof($words) - 1)],'authorId' => 1,'state' => 1,'isUpdated' => 0,];});}/*** 生成模拟的数据,需seederRollback 成对出现*/public function seeder(){$articles = factory(ArticlesModel::class, 10)->make();foreach ($articles as $article) { // 注意: article为引用对象,不是copyif ($article->isRecommend) {$article->recommendTime = time();}$article->save();}}/*** getArticleList 测试数据* @return array*/public function getArticleListDataProvider(){return [[1, "搜索", 1, 10, 1],[2, "搜索", 1, 10, 0],[2, null, 1, 10, 0],[3, "搜索", 1, 10, 0],[1, null, 1, 10, 1],[2, null, 1, 10, 0],[3, null, 1, 10, 0],];}/*** @dataProvider getArticleListDataProvider*/public function testGetArticleList($type, $searchText, $page, $pageSize, $expceted){$rst = self::$model->getArticleList($type, $searchText, $page, $pageSize);$this->assertGreaterThanOrEqual($expceted, sizeof($rst));$rst = self::$model->getArticleCount($type, $searchText);$this->assertGreaterThanOrEqual($expceted, $rst);}/*** addArticle 测试数据* @return array*/public function addArticleDataProvider(){return [[['id' => 273,'uri' => 'dddddddddd0123'],'save',0],[['id' => 274,'uri' => 'dddddddddd123'],'publish',0],[['id' => 275,'uri' => 'dddddddddd456'],'preview',0],];}/*** @dataProvider addArticleDataProvider*/public function testAdd($data, $action, $expected){$rst = self::$model->addArticle($data, $action);if ($rst) {self::$model::where('id', $rst)->delete();}$this->assertGreaterThanOrEqual($expected, $rst);}public function testGetArticleInfo(){$rst = self::$model->getArticleInfo(263, 0);$this->assertGreaterThanOrEqual(1, sizeof($rst));$rst = self::$model->getArticleInfo(2000, 1);$this->assertEquals(0, sizeof($rst));}/*** 回滚模拟的数据到初始状态*/public function seederRollback(){self::$model::where('id', '>=', 263)->where('id', '<=', 272)->delete();}
}

运行测试

cd {APPROOT}/tests/Cases/Headline
# mv phpunit-debug-custom.xml -> phpunit-debug.xml
../../../vendor/bin/phpunit --verbose -c phpunit-debug.xml

参考

PHPUnit 5.0 官方中文手册

PHPUnit实践三(构建模块化的测试单元)相关推荐

  1. 《 嵌入式系统设计与实践》一一3.6 测试硬件(和软件)

    3.6 测试硬件(和软件) 虽然我强烈建议准备好工具箱.数字万用表和示波器,但是,如果大家没有准备好独自拥有这些,那么将这些留给硬件工程师也在情理之中.作为一个软件工程师,更重要的是将用于测试硬件的软 ...

  2. 基于Spark的机器学习实践 (三) - 实战环境搭建

    0 相关源码 1 Spark环境安装 ◆ Spark 由scala语言编写,提供多种语言接口,需要JVM ◆ 官方为我们提供了Spark 编译好的版本,可以不必进行手动编译 ◆ Spark安装不难,配 ...

  3. java class 静态模块_Java API 最佳设计实践:在模块化和非模块化 Java 环境中使用...

    了解在设计 Java API 时应该运用的一些 API 设计实践.这些实践通常很有用,而且可确保 API 能在诸如 OSGi 和 Java Platform Module System (JPMS) ...

  4. 张萍萍 计科高职13-1 201303014010 实践三结对项目

    实践三结对项目   学号: 201303014010   姓名:张萍萍    班级:计科(高职)13-1 一.题目简介: 设计一个名为MyPoint的类,表示一个带x坐标和y坐标的点.该类包括: 两个 ...

  5. 如何设计高效测试用例_高效的企业测试-单元和用例测试(2/6)

    如何设计高效测试用例 在本系列的第一部分中,我们看到了有效测试应满足的一些普遍适用的原则和约束. 在这一部分中,我们将仔细研究代码级单元测试和组件或用例测试. 单元测试 单元测试验证单个单元(通常是类 ...

  6. 高效的企业测试-单元和用例测试(2/6)

    在本系列的第一部分中,我们看到了有效测试应满足的一些普遍适用的原则和约束. 在这一部分中,我们将仔细研究代码级单元测试以及组件或用例测试. 单元测试 单元测试验证单个单元(通常是类)的行为,而忽略或模 ...

  7. ci 数据库异常捕获_系统地捕获错误:如何通过4个步骤构建GitLab CI测试管道

    ci 数据库异常捕获 by Joyz 通过乔伊斯 系统地捕获错误:如何通过4个步骤构建GitLab CI测试管道 (Catch bugs systematically: how to build a ...

  8. matlab编写转台程序,基于Matlab三轴惯导测试转台结构分析.doc

    基于Matlab三轴惯导测试转台结构分析 基于Matlab三轴惯导测试转台结构分析 摘 要:三轴惯导测试转台作为惯导测试设备,其精度直接影响惯导设备的精度,而中框回转精度在三轴精度相对较差.影响其中框 ...

  9. Site-to-Site VPN配置和调试实践:构建安全的远程网络连接

    Site-to-Site VPN配置和调试实践:构建安全的远程网络连接 [实验目的] 理解Site to Site VPN的含义. 掌握Site to Site VPN的含义. 验证配置. [实验拓扑 ...

最新文章

  1. Unable to open the physical file XXX.mdf
  2. 华为为什么能成全球第一?告诉你三个真相!
  3. python 文件路径格式化_python 存储为txt文件路径
  4. matlab imwrite将图像保存到其他目录
  5. (Matlab问题解决)运行matlab程序后,工作区不能显示变量
  6. Android 向服务器发送XML数据及调用webservice
  7. LeetCode刷题(47)--Gray Code
  8. mongodb查询优化
  9. php高德地图计算距离接口,高德地图计算两坐标之间距离
  10. 无人车业务中的视觉三维重建
  11. boot spring 获取请求端口浩_Spring boot 无端口模式启动
  12. zmeet会议在金融、教育和场景特点与产品功能方案
  13. python机械数据分析_记一次小机器的 Python 大数据分析
  14. Windows OCR推荐
  15. java.lang.ClassCastException: org.apache.hadoop.mapreduce.lib.input.FileSplit cannot be cast to org
  16. 番外篇:常见安全漏洞及解决方案
  17. 07 ,矩阵的转置,矩阵的行列式,方阵 ( 2阶行列式,3阶行列式,n 阶行列式 ) :
  18. 计算机英语读音在线,computer是什么意思_computer翻译_读音_用法_翻译
  19. Unity Spine 换装
  20. html2canvas 下载图片 报网络错误

热门文章

  1. 理解jQuery对象$.html
  2. windows XP下Python2.7包管理工具安装-setuptool,pip、distribute、nose、virtualenv
  3. Nutch插件开发及发布流程
  4. c++ hook 钩子的使用介绍
  5. MyEclipse断点调试
  6. 搜索引擎的时效性需求满足
  7. 开发自己的山寨Android注解框架
  8. mac os下valgrind的安装
  9. JS子窗口调用父窗口中的函数
  10. Linux下查看显示器输出状态以及修改显示器工作模式(复制 or 扩展)