工要善其事,必先利其器,首先我們准備的是強大開發工具IDE : PhpStorm
我們用的是最新版 phpstorm 2019.3 (網上有破解激活方法)
安裝環境:composer
官網安裝教程: https://getcomposer.org/download/
windows安裝composer:
最簡單的方法,新建文件composer-setup.bat 編輯器打開 將下面的代碼拷貝進去,雙擊運行,完成后目錄下就會下載一個文件composer.phar
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" php -r "if (hash_file('sha384', 'composer-setup.php') === 'baf1608c33254d00611ac1705c1d9958c817a1a33bce370c0595974b342601bd80b92a3f46067da89e3b06bff421f182') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" php composer-setup.php php -r "unlink('composer-setup.php');"
用 php composer.phar 命令就可以開啟使用 composer之旅啦:
php composer.phar --version
當然每次敲 php composer.phar 代碼太麻煩了,有沒有辦法省略為 直接composer命令,可以這樣做
1. 把當前目錄 E:\PHPServer\phplibrary 添加到系統環境變量$PATH中:
點擊編輯,彈出窗口:
在當前目錄 E:\PHPServer\phplibrary 下 新建一個 composer.bat 文件,將下面代碼拷貝進去保存即可。以后就可以直接使用composer命令了。
@php "%~dp0composer.phar" %*
省去輸入.bat的做法,在當前目錄 E:\PHPServer\phplibrary 下 新建一個 composer 文件(無后綴名),將下面代碼拷貝進去保存即可。
#!/usr/bin/env sh # php /path/to/composer.phar $* php `dirname $0`/composer.phar $*
PHP Composer各大廠商鏡像全鏡像地址,如果使用composer安裝過程過於緩慢,可以切換為國內鏡像:
https://www.cnblogs.com/phplog/articles/11297728.html
安裝phpuinit:
官網下載安裝教程: https://phpunit.de/getting-started/phpunit-8.html
幾個版本的包下載地址(官網)
https://phar.phpunit.de/phpunit-8.phar
https://phar.phpunit.de/phpunit-7.phar
https://phar.phpunit.de/phpunit-6.phar
https://phar.phpunit.de/phpunit-5.phar
備用下載地址:
http://phar.phpunit.cn/phpunit-4.8.phar
http://phar.phpunit.cn/phpunit-7.0.phar
http://phar.phpunit.cn/phpunit-8.0.phar
http://phar.phpunit.cn/phpunit.phar (最新版的包)
linux安裝:
wget http://phar.phpunit.cn/phpunit-7.0.phar chmod +x phpunit-7.0.phar mv phpunit-7.0.phar /usr/local/bin/phpunit phpunit --version
windows安裝:
cd E:\PHPServer\phplibrary curl -O http://phar.phpunit.cn/phpunit.phar # phpunit --version
在當前目錄 E:\PHPServer\phplibrary 下 新建一個 phpunit.bat 文件,將下面代碼拷貝進去保存即可。以后就可以直接使用phpunit命令了。
@php "%~dp0phpunit.phar" %*
省去輸入.bat的做法,在當前目錄 E:\PHPServer\phplibrary 下 新建一個 phpunit 文件(無后綴名),將下面代碼拷貝進去保存即可。
#!/usr/bin/env sh
# php /path/to/phpunit.phar $* php `dirname $0`/phpunit.phar $*
phpunit各個版本支持情況,可以查閱網址: http://www.phpunit.cn
主版本 | 初始版本 | PHP兼容性 | 支持 |
PHPUnit 8 | 2019年2月1日 | PHP 7.2, PHP 7.3, PHP 7.4 | 在2021年2月5日結束支持 |
PHPUnit 7 | 2018年2月2日 | PHP 7.1, PHP 7.2, PHP 7.3 | 在2020年2月7日結束支持 |
PHPUnit 6 | 2017年2月3日 | PHP 7.0, PHP 7.1, PHP 7.2 | 在2019年2月1日結束支持 |
PHPUnit 5 | 2015年10月2日 | PHP 5.6, PHP 7.0, PHP 7.1 | 在2018年2月2日結束支持 |
PHPUnit 4 | 2014年3月7日 | PHP 5.3, PHP 5.4, PHP 5.5, PHP 5.6 | 在2017年2月3日結束支持 |
PHPUnit 8於2019年2月1日發布。它將支持PHP 7.2, PHP 7.3, PHP 7.4.
使用 PhpStorm 調試 PHPUnit 單元測試:
首先展示下我的運行效果:
首先 配置 php 運行版本(我在系統環境變量$PATH添加的是 E:\PHPServer\phpStudy_v8\Extensions\php\php7.2.9nts (php7.2版本),所以IDE也要改成一致) :
Languages & Frameworks > PHP > Test Frameworks
點擊 + 新增一個 PHPUnit Local
執行單元測試
方式1: Phpstorm方式,當前測試類右鍵Run即可
方式2:命令行方式,進入項目目錄執行
要引入命名空間文件,讓其能自動加載,我們可以編寫一個autoload.php , 或 Bootstrap.php ,當然文件名可以隨意。
<?php
# Bootstrap.php 文件 function autoloader($dir) { spl_autoload_register(function ($class) use ($dir) { if (class_exists($class)) { return true; } $pathPsr4 = $dir."/".strtr($class, '\\', DIRECTORY_SEPARATOR) . ".php"; if (file_exists($pathPsr4)){ include_once $pathPsr4; } return true; }); } define('BOOT_ROOT', __DIR__); autoloader(BOOT_ROOT);
創建一個單元測試文件 EmailTest.php:
<?php # EmailTest.php 文件 namespace tests; require_once __DIR__ . '/../Bootstrap.php'; use PHPUnit\Framework\TestCase; use src\Email; final class EmailTest extends TestCase { public function __construct($name = null, array $data = [], $dataName = '') { parent::__construct($name, $data, $dataName); } public function testCanBeCreatedFromValidEmailAddress(): void { $this->assertInstanceOf( Email::class, Email::fromString('user@example.com') ); } public function testCannotBeCreatedFromInvalidEmailAddress(): void { $this->expectException(\InvalidArgumentException::class); Email::fromString('invalid'); } public function testCanBeUsedAsString(): void { $this->assertEquals( 'user2@example.com', Email::fromString('user@example.com') ); } }
里面的代碼 引入了autoload 的 Bootstrap文件: require_once __DIR__ . '/../Bootstrap.php';
所以phpunit可以不指定 bootstrap選項來運行:
phpunit tests/EmailTest.php
如果沒有這句文件引用進來,就得手動指定 autoload配置了:
# 指定autoload配置: phpunit --bootstrap Bootstrap.php tests/EmailTest.php
用 PhpStorm 進行單元測試:
手動指定 bootstrap file :
點擊選擇文件,右鍵菜單Debug
或者點擊工具欄上的運行按鈕:
執行結果:
phpstorm就會自動加上phpunit運行參數來運行測試 phpunit,例如:
E:\PHPServer\phpStudy_v8\Extensions\php\php7.2.9nts\php.exe -dxdebug.remote_enable=1 -dxdebug.remote_mode=req -dxdebug.remote_port=9100 -dxdebug.remote_host=127.0.0.1 E:\PHPServer\phplibrary\phpunit.phar --bootstrap E:\Develop-Work\my-project-list\my-work-list\phpTest\Bootstrap.php --no-configuration tests\EmailTest2 E:\Develop-Work\my-project-list\my-work-list\phpTest\tests\EmailTest2.php --teamcity
另外,配置 phpunit.xml (可選),例如:
安裝 thinkphp 5.1 :
文檔: https://www.kancloud.cn/manual/thinkphp5_1/353948
composer命令執行安裝:
composer create-project topthink/think=5.1.* thinkapp
執行完成:
將生成一個目錄 thinkapp
編輯 public/index.php, 原代碼:
<?php // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- // | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st <liu21st@gmail.com> // +---------------------------------------------------------------------- // [ 應用入口文件 ] namespace think; // 加載基礎文件 require __DIR__ . '/../thinkphp/base.php'; // 支持事先使用靜態方法設置Request對象和Config對象 // 執行應用並響應 Container::get('app')->run()->send();
比如我們開發項目可能加個常量等,修改 public/index.php文件:
<?php // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- // | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st <liu21st@gmail.com> // +---------------------------------------------------------------------- // [ 應用入口文件 ] namespace think; define('ROOT_PATH', __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR); define('APP_PATH', ROOT_PATH . 'application' . DIRECTORY_SEPARATOR); define('ADDON_PATH', ROOT_PATH . 'addons' . DIRECTORY_SEPARATOR); // 加載基礎文件 require ROOT_PATH . 'thinkphp' . DIRECTORY_SEPARATOR . 'base.php'; // 支持事先使用靜態方法設置Request對象和Config對象 // 執行應用並響應 Container::get('app')->run()->send();
修改 console控制台文件: think
原代碼:
#!/usr/bin/env php <?php // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- // | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: yunwuxin <448901948@qq.com> // +---------------------------------------------------------------------- namespace think; // 加載基礎文件 require __DIR__ . '/thinkphp/base.php'; // 應用初始化 Container::get('app')->path(__DIR__ . '/application/')->initialize(); // 控制台初始化 Console::init();
修改 think 文件代碼:
#!/usr/bin/env php <?php // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- // | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: yunwuxin <448901948@qq.com> // +---------------------------------------------------------------------- namespace think; define('ROOT_PATH', __DIR__ . DIRECTORY_SEPARATOR); define('APP_PATH', ROOT_PATH . 'application' . DIRECTORY_SEPARATOR); define('ADDON_PATH', ROOT_PATH . 'addons' . DIRECTORY_SEPARATOR); // 加載基礎文件 require ROOT_PATH . '/thinkphp/base.php'; // 應用初始化 Container::get('app')->path(__DIR__ . '/application/')->initialize(); // 控制台初始化 Console::init();
創建和配置網站:
設置偽靜態:
if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s=/$1 last; break; }
最后瀏覽器訪問:
查看thinkphp 5.1的版本:
打開 thinkphp/library/think/App.php 可以看到版本號
或者通過命令查看 :
php think version
配置 phpstorm :
安裝thinkphp 單元測試:
文檔地址: https://www.kancloud.cn/manual/thinkphp5_1/354125
執行composer 命令進行安裝:
composer require topthink/think-testing=2.0.*
成功安裝后,根目錄就會多出 tests文件夾和 phpunit.xml 文件
如果沒有生成這兩個的文件夾和文件,可以到 https://github.com/top-think/think-testing 下載示例。
執行 composer update 更新包到最新:
composer update
執行 命令 php think unit 進行單元測試:
在 tests 文件夾 ,右鍵, New > PHP Test > PHPUint Test 創建一個新的單元測試文件 NewTest.php :
生成的 NewTest.php 文件:
新生成的 tests\NewTest.php 原代碼:
<?php use PHPUnit\Framework\TestCase; class NewTest extends TestCase { }
編輯 tests\NewTest.php文件:
<?php # tests/NewTest.php 文件 # 注意: NewTest 是繼承 PHPUnit\Framework\TestCase, 不是繼承 \think\testing\TestCase # 所以, php think unit 也只能測試 普通的 單元測試方法, 像 $this->visit('/index/test/show')->see('show_test'); 這種就會提示找不到 visit方法 # 要想能支持 visit, see方法, 只能改繼承父類方法: class NewTest extends \think\testing\TestCase use PHPUnit\Framework\TestCase; class NewTest extends TestCase { #protected $baseUrl = 'http://www.thinkapp.com'; public function testBasicFunctions() { $this->assertTrue(true); $this->assertEquals(2, 1 + 1); $app = new \app\index\controller\Test(); // 假設 index/test/show 方法返回的字符串中包含 "show_test" $this->assertContains('show_test', $app->show()); } public function testTest() { $stack = []; $this->assertEquals(0, count($stack)); } public function testSomethingIsTrue() { $this->assertTrue(true); } public function testSum() { $obj = new \app\index\controller\Test(); $this->assertEquals(6, $obj->testNum(2, 3)); } // 測試出錯代碼 public function testError() { $obj = new \app\index\controller\Test(); $this->assertEquals(6, $obj->testError(2, 3)); } }
在 application/index/controller 目錄下 創建一個 Test.php 文件
<?php # application/index/controller/Test.php 文件 namespace app\index\controller; class Test { public function testNum($a, $b) { $c = $a * $b; return $c; } public function testError($a, $b) { $c = $a * $b; return $z; // 故意寫錯成 $z } public function show() { return 'show_test'; } }
命令行再次執行 php think unit 進行單元測試:
另外thinkphp自帶的測試單元方法:
在 tests 文件夾下 新建 ThinkTest.php (這個就支持的比較全面)
<?php # tests/ThinkTest.php 文件 # 注意: ThinkTest 是繼承 \think\testing\TestCase, 不是繼承 \PHPUnit\Framework\TestCase # 所以, php think unit 能支持 thinkphp 自身測試單元的 visit, see方法, 例如 $this->visit('/index/test/show')->see('show_test'); # 所有的 PHPUnit 的方法都支持。 namespace tests; class ThinkTest extends \think\testing\TestCase { protected $baseUrl = 'http://www.thinkapp.com'; public function testBasicFunctions() { $app = new \app\index\controller\Test(); // 假設 index/test/show 方法返回的字符串中包含 "show_test" $this->assertContains('show_test', $app->show()); } public function testBasicExample() { $this->visit('/index/test/show')->see('show_test'); } }
執行 php think unit 命令后的效果:
可單獨運行phpunit命令的單元測試文件,
方法:例如在tests文件夾下 新建 UnitTest.php 文件:
<?php # tests/UnitTest.php 文件 # 注意: UnitTest 是繼承 \PHPUnit\Framework\TestCase # UnitTest 可以單獨執行 phpunit命令測試 thinkphp 框架項目。 # 執行命令: phpunit tests/UnitTest.php namespace tests; use PHPUnit\Framework\TestCase; class UnitTest extends TestCase { public function __construct($name = null, array $data = [], $dataName = '') { # 幾個常量定義,摘抄自 public/index.php 里的文件定義 defined('ROOT_PATH') or define('ROOT_PATH', __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR); defined('APP_PATH') or define('APP_PATH', ROOT_PATH . 'application' . DIRECTORY_SEPARATOR); defined('ADDON_PATH') or define('ADDON_PATH', ROOT_PATH . 'addons' . DIRECTORY_SEPARATOR); // 引入需要的環境 require_once ROOT_PATH . '/thinkphp/base.php'; // 初始化 App 對象,並將 APP_PATH 指向項目的 application 目錄 //\think\App::getInstance()->path(__DIR__ . '/../application/')->initialize(); \think\Container::get('app')->path(__DIR__ . '/../application/')->initialize(); parent::__construct($name, $data, $dataName); } public function testSomethingIsTrue() { $this->assertTrue(false); } public function testSum() { $obj = new \app\index\controller\Test(); $this->assertEquals(6, $obj->testNum(2, 3)); } public function testError() { $obj = new \app\index\controller\Test(); $this->assertEquals(6, $obj->testError(2, 3)); } }
執行 phpunit 命令進行單元測試:
phpunit tests/UnitTest.php
配置編輯器:
在 文件 UnitTest.php 右鍵 > Debug (PHPUnit)
更改默認的cmd客戶端,比如更改成 Git Bash (路徑:D:\Program Files\Git\bin\sh.exe)
修改: Settings > Tools > Terminal > Application settings > Shell path, 輸入 D:\Program Files\Git\bin\sh.exe
推薦更強大的單元測試工具:codeception單元測試
請查看我的另一篇文章介紹:
phpstorm集成codeception單元測試 ( https://www.cnblogs.com/phplog/articles/12058369.html )
tp 3.2 的單元測試可以參考(沒測試過,請自行測試):
https://www.kancloud.cn/code7/tpunit/378491
https://github.com/CODE7070/TPUNIT
phpunit assert斷言分類整理
布爾類型
方法名 | 含義 | 參數 | 返回值 |
---|---|---|---|
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字符串不相等 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
phpunit中相關的幾個斷言:
assertTrue / assertFalse 斷言是否為真值還是假
assertEquals 判斷輸出是否和預期的相等
assertGreaterThan 斷言結果是否大於某個值,同樣的也有lessThan(小於), greaterThanOrEqual(大於等於),
lessThanOrEqual (小於等於).
assertContains 判斷輸入是否包含指定的值
assertType 判斷是否屬於指定類型
assertNull 判斷是否為空值
assertFileExists 判斷文件是否存在
assertRegExp 根據正則表達式判斷
其他參數資料:
上面單元測試實例源碼已經放到Github上了: https://github.com/lajox/thinkphp-codeception-example
關於斷言: https://phpunit.readthedocs.io/zh_CN/latest/
PHPUnit文檔: https://phpunit.de/manual/6.5/en/writing-tests-for-phpunit.html
中文文檔: http://www.phpunit.cn/getting-started.html
中文文檔:http://www.phpunit.cn/manual/current/zh_cn/installation.html
https://phpunit.readthedocs.io/zh_CN/latest/index.html
https://www.cnblogs.com/martini-d/p/phpstorm-pei-zhiphpunit.html#autoid-4-1-0