在項目開發中,須要使用到ThinkPHP 5,爲了編寫單元測試,解決了幾個難題,特此紀錄分享一下。php
在看雲上,有TP5官方關於單元測試的使用說明,連接是:https://www.kancloud.cn/manual/thinkphp5/182511html
但上面的說明過於簡單,對於實際使用幫助有限。git
對於一直鍾情於自動化單元測試以及PHPUnit原生單元測試的我,決定對此優化一番,引入並在ThinkPHP 5下使用原生PHPUnit。github
在tests目錄下,建立一個phpunit目錄,而後建立兩個文件:測試啓動文件bootstrap.php和單元測試的配置文件phpunit.xml。thinkphp
測試啓動文件bootstrap.php,能夠參考項目的啓動文件,複製過來後調整下,例如這樣:bootstrap
<?php // 定義應用目錄 define('APP_PATH', __DIR__ . '/../../application/'); define('APP_DEBUG', true); //開啓調試模式 define("APP_STATUS", "tests"); //定義爲本地環境 define("RUNTIME_PATH", __DIR__ . "/../../runtime/"); //定義緩存目錄 require APP_PATH . '/define.php'; // ThinkPHP 引導文件 // 加載基礎文件 require __DIR__ . '/../../thinkphp/base.php'; // 加載應用 \think\Loader::addNamespace('app', APP_PATH); // 兼容舊版本的PHPUnit if (!class_exists('PHPUnit_Framework_TestCase')) { class PHPUnit_Framework_TestCase extends PHPUnit\FrameWork\TestCase { } } // 手動再引入一次測試配置 \think\Config::load(APP_PATH . '/tests/test.php'); // 手動引入框架和應用的函數 require_once APP_PATH . '../thinkphp/helper.php'; require_once APP_PATH . 'common.php';
對於phpunit.xml配置文件,能夠這樣寫:api
<?xml version="1.0" encoding="UTF-8"?> <phpunit backupGlobals="false" backupStaticAttributes="false" colors="true" bootstrap="./bootstrap.php" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" syntaxCheck="false" > <php> <ini name="intl.default_locale" value="en"/> <ini name="intl.error_level" value="0"/> <ini name="memory_limit" value="-1"/> </php> <testsuites> <testsuite name="Test Suite"> <directory suffix="Test.php">./</directory> <directory suffix="Test.php">./application</directory> </testsuite> </testsuites> <filter> <whitelist processUncoveredFilesFromWhitelist="true"> <directory suffix=".php">../../application</directory> </whitelist> </filter> </phpunit>
下面編寫一個簡單的測試用例,試運行一下。在phpunit下建立一個demo目錄,並建立TestCaseClass.php文件。此時結構以下:緩存
$ tree ./phpunit ./phpunit ├── bootstrap.php ├── demo │ └── TestCaseClass.php └── phpunit.xml
TestCaseClass.php文件代碼是:bash
<?php use PHPUnit\Framework\TestCase; namespace tests\demo; class TestCaseClass extends \PHPUnit_Framework_TestCase { public function testHere() { $this->assertTrue(true); } }
這樣編寫成功後,就能夠試運行了。app
$ phpunit ./demo/TestCaseClass.php PHPUnit 5.7.25 by Sebastian Bergmann and contributors. . 1 / 1 (100%) Time: 121 ms, Memory: 10.00MB OK (1 test, 1 assertion)
後面就能夠繼續這樣編寫原生的PHPUnit單元測試啦。
下面就要爲TP5的項目代碼編寫單元測試了,但每次都要人工手動重複編寫測試代碼是一件很累人、很耗時、很低率的工做。有沒更好的技能?有!
參考我曾經編寫的腳本工具:[PHPUnit]自動生成PHPUnit測試骨架腳本-提供您的開發效率【2015升級版】
如今已經成爲PhalApi開源框架內置的腳本命令了。PhalApi是一個專一於接口開發的開源框架,所以咱們能夠把PhalApi的phalapi-buildtest腳本命令整合到ThinkPHP 5 的項目裏,
很是重要的連接
使用說明和詳細的官方文檔:PhalApi 2.x 單元測試
腳本命令Github下載地址(須要同時下載這兩個文件):
https://github.com/phalapi/phalapi/blob/master-2x/bin/phalapi-buildtest
https://github.com/phalapi/phalapi/blob/master-2x/bin/build_test.php
下載後放到tests/phpunit目錄下,此時文件結構以下:
$ tree ./phpunit ./phpunit ├── bootstrap.php ├── build_test.php ├── demo │ └── TestCaseClass.php ├── phalapi-buildtest └── phpunit.xml
準備好後,就能夠開始生成單元測試的代碼啦!
例如,可執行:
$ ./phalapi-buildtest ../../application/controller/Site.php 'app\controller\Site' > ./controller/SiteTest.php
生成後,即可執行。
正常狀況下,進行單個單元測試時,如下測試代碼是能夠的:
public function testLogin() { $_POST['email'] = 'phpunit123'; $_POST['password'] = '123456'; $_POST['remember'] = '1'; $rs = $this->appcontrollerSite->login(); $this->assertEquals(1, $rs['code']); }
對應的源代碼是:
<?php class Site extends Controller { public function login() { $username = input('post.email'); $password = input('post.password'); $remember = input('post.remember/d', 0); // todo } }
可是,若是執行所有單元測試的話,傳給controller的$_POST參數就失效了。這是由於ThinkPHP5的Request是一個單例,而且在think\Request::$post變量中緩存了POST參數,致使後面的參數不生效。
爲此,須要這樣調整傳遞參數:
public function testLogin() { $_POST['email'] = 'phpunit123'; $_POST['password'] = '123456'; $_POST['remember'] = '1'; // 加多這兩行,重置POST參數 $params = ['POST' => $_POST]; \think\Request::create('/', 'POST', $params); $rs = $this->appcontrollerSite->login(); $this->assertEquals(1, $rs['code']); }
發現了一篇寫得很讚的文章:PHPUnit簡介及使用(thinkphp5的單元測試安裝及使用)