xhqiang 2019-06-30
本系列教程所有的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配置
<?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; } }
本文件是我们单独为某些正在测试的测试用例,直接编写的xml,可以不用来回测试,已经测试成功的测试用例了,最后全部编写完测试用例,再用正式phpunit.xml即可,具体在运行测试阶段看如何指定配置
<?xml version="1.0" encoding="UTF-8"?> <phpunit bootstrap="../../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为引用对象,不是copy if ($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