1. 前情提要
群里有人问怎么单元测试.说实话青岛的公司还真没有几个写单元测试的.天天加班,需求都做不完.
当然如果上线了,暂时没事干还是最好把单元测试补上.
刚开始工作的时候,用的破解的Zend,非常不好用,然后换到Netbeans.相对来说顺手了很多.对PHP的支持也还行.14年换成了PHPStorm.结果发现一直没有记录PHPStorm单元测试的笔记.
2. PHPStorm配置单元测试
完整的文档:http://www.phpunit.cn/manual/current/zh_cn/phpunit-book.html
2.1. 安装PHPUnit
composer require phpunit/phpunit
2.2. PhpStorm配置测试框架
首先配置PHP
- 选择PHP版本
- 添加PHP
- Vagrant和Docker Compose都是直接选择配置文件路径即可
- Deployment configuration没有用过
- Docker就是配置本地的IP和端口
- 如果是远程,配置对应的映射.
然后配置测试框架
直接选择上面配置的PHP即可.
可选配置phpunit.xml
项目路径下配置一个phpunit.xml,如果是框架,就是对应的web目录.或者web目录/test/下
PHPStorm不需要配置这个.如果需要使用各种高级功能.还是需要研究以下
以下是一个模板
<?xml version="1.0" encoding="UTF-8"?>
<!--bootstrap指定启动测试时, 先加载vendor/autoload.php-->
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<!--testsuite指定测试文件的目录-->
<testsuite>
<directory suffix="Test.php">./tests</directory>
</testsuite>
<!--filter过滤依赖文件的位置-->
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
</phpunit>
3. 例子
3.1. 测试某方法
很早之前的一个例子
Walk.php
require_once "vendor/autoload.php";
class Walk
{
private $option_keys = [
'ownADog',
'tired',
'haveNotWalkedForDays',
'niceOutside',
'bored'];
private $options = [];
public function __construct()
{
foreach ($this->option_keys as $key) {
$this->options[$key] = true;
}
}
public function move()
{
if ($this->shouldWalk()) {
$this->goForAWalk();
}
}
public function shouldWalk()
{
return ($this->timeToWalkTheDog() || $this->feelLikeWalking());
}
public function timeToWalkTheDog()
{
return ($this->options['ownADog'] && (!$this->options['tired'] || $this->options['haveNotWalkedForDays']));
}
public function feelLikeWalking()
{
return (($this->options['niceOutside'] && !$this->options['tired']) || $this->options['bored']);
}
public function __set($name, $value)
{
// TODO: Implement __set() method.
if (in_array($name, $this->option_keys)) {
$this->options[$name] = $value;
}
}
private function goForAWalk()
{
echo "Going for a walk";
}
}
$walk = new Walk();
$walk->move();
添加测试用例:
勾选需要测试的方法
WalkTest.php
use PHPUnit\Framework\TestCase;
require_once "vendor/autoload.php";
require_once "Walk.php";
class WalkTest extends TestCase
{
/**
* @var Walk
*/
protected $object;
/**
* 安装准备,比如,打开网络连接等.
* 该方法在测试执行前执行
*/
protected function setUp(): void
{
parent::setUp(); // TODO: Change the autogenerated stub
$this->object = new Walk();
}
/**
* 销毁,比如,关闭网络连接等.
* 该方法在测试执行后调用
*/
protected function tearDown(): void
{
parent::tearDown(); // TODO: Change the autogenerated stub
}
public function testTimeToWalkTheDog_default()
{
//当然也是可以直接把初始化过程写在这里的.
print __FUNCTION__;
$this->assertTrue($this->object->timeToWalkTheDog());
}
public function testTimeToWalkTheDog_haveNoDog_shouldReturnFalse()
{
print __FUNCTION__;
$this->object->ownADog = false;
$this->assertTrue(!$this->object->timeToWalkTheDog());
}
}
3.2. 手动测试
#手动测试单文件
phpunit --bootstrap Walk.php WalkTest.php
# 执行某目录
phpunit test
# 其实就是把Test文件放到专门的test目录中
src/
└---- Walk.php
test/
└---- WalkTest.php
3.3. PHPStorm一键测试
4. TDD原则
- 编写一个测试
- 尚未编写出可以满足测试的代码,测试失败.
- 实现最少的功能,使测试通过
- 重复上买了的步骤
5. 注意
- 被测试的文件最好不要又什么include
- 注意自动加载的类是否正确加载了