前言
tp5自带了phpunit,但是,其phpunit版本很老,有时候集成还会出错,反正我是集成之后没法用的,并且我又习惯了phpunit6.5的语法,所以在项目中想使用tp5集成phpunit 6.5,而不是用用tp默认的单元测试工具。
问题
tp5集成了phpunit后,最大的问题是类的自动加载问题。通常我们会在项目的extend目录下写一些自己的类库,但是在单元测试的时候会报类找不到。
namespace util;
class ConfigMap
{
// 车辆配置
const CONFIGS = [
// 车辆类型
'viche_type' => [
'1' => '栏板车',
'2' => '高栏车'
]
];
/**
* 获取配置
* @param $keys string 键, 传空值,表示获取对应type下的所有配置,多个用逗号隔开
*/
public static function getConfs($names = '')
{
// TODO
}
}
如上,在extend的util目录下,有个ConfigMap类,这个类很简单,就是配置一些数据,通过getConfs方法可以获取配置数据。
我想对此类写单元测试,在项目根目录下写一个phpunit.xml文件,配置如下
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./application</directory>
</whitelist>
</filter>
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
</php>
</phpunit>
bootstrap选项用于引入自动加载的文件,利于我们通过命名空间自动加载类库。
然后在tests目录下编写单元测试。
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
use util\ConfigMap;
class ConfigMapTest extends TestCase
{
/**
* 测试getConfs方法
* @covers \util\ConfigMap::getConfs
*/
public function testGetConfs()
{
$config_origin = ConfigMap::CONFIGS;
$config = ConfigMap::getConfs();
$this->assertEquals($config_origin, $config);
}
}
在项目根目录运行单元测试,如下:
./vendor/bin/phpunit -c phpunit.xml tests/Unit/ConfigMapTest.php
结果会报错:

报错的原因在于thinkphp实现了一套自己的自动加载规则,它可以自动加载composer下定义的类库,也可以加载extend下的自定义类库。但是vendor/autoload.php无法加载extend目录下自定义的类库,所以,我自定义了一个自动加载文件,放在tests目录下,名称为autoloader.php
define('THINK_VERSION', '5.0.24');
define('THINK_START_TIME', microtime(true));
define('THINK_START_MEM', memory_get_usage());
define('EXT', '.php');
define('DS', DIRECTORY_SEPARATOR);
defined('THINK_PATH') or define('THINK_PATH', __DIR__ . DS . '..' . DS . 'thinkphp' . DS);
define('LIB_PATH', THINK_PATH . 'library' . DS);
define('CORE_PATH', LIB_PATH . 'think' . DS);
define('TRAIT_PATH', LIB_PATH . 'traits' . DS);
defined('APP_PATH') or define('APP_PATH', THINK_PATH . '..' . DS . 'application' . DS);
defined('ROOT_PATH') or define('ROOT_PATH', dirname(realpath(APP_PATH)) . DS);
defined('EXTEND_PATH') or define('EXTEND_PATH', ROOT_PATH . 'extend' . DS);
defined('VENDOR_PATH') or define('VENDOR_PATH', ROOT_PATH . 'vendor' . DS);
defined('RUNTIME_PATH') or define('RUNTIME_PATH', ROOT_PATH . 'runtime' . DS);
defined('LOG_PATH') or define('LOG_PATH', RUNTIME_PATH . 'log' . DS);
defined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH . 'cache' . DS);
defined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH . 'temp' . DS);
defined('CONF_PATH') or define('CONF_PATH', APP_PATH); // 配置文件目录
//var_dump(CONF_PATH);exit;
defined('CONF_EXT') or define('CONF_EXT', EXT); // 配置文件后缀
defined('ENV_PREFIX') or define('ENV_PREFIX', 'PHP_'); // 环境变量的配置前缀
// 环境常量
define('IS_CLI', PHP_SAPI == 'cli' ? true : false);
define('IS_WIN', strpos(PHP_OS, 'WIN') !== false);
// 载入Loader类
require CORE_PATH . 'Loader.php';
// 注册自动加载
\think\Loader::register();
// 初始化,加载函数等
\think\App::initCommon();
然后在phpunit.xml中使用此文件,如下:

这样,就可以使用我们自定义的自动加载规则了。
但是,运行后依然报错,原因是composer下的autoload_static.php重复引用了,如下:

改造一下think\Loader.php,将290行的require改为require_once,如下:

再次运行刚才的命令,单元测试就跑起来了:

