刘懿东
测试
为什么要测试?
测试是开发php应用过程中重要的一步,但往往被忽视。很多php开发者都不测试,因为他们觉得测试是不必要的负担,投入的时间多而收益却很少;有些开发者可发者可能不知道如何测试,因为测试工具太多,学习曲线太陡
通过本章学习,希望你愿意测试php代码,把测试看成整个工作流程不可分割的一部分,在开发应用开发、过程中和结束后都要测试
编写测试是为了确保php应用始终能够按照我们预期的方式运行
你是不是经常害怕把应用部署到生产环境?
测试能降低这种不确定性,还能让我们带着自信编写和部署代码
很多人觉得没有足够的时间编写测试,这是鼠目寸光的想法
安装测试所需的功能和编写测试是要花时间,但这是明知的投资,未来会得到回报
测试能协助我们编写一开始可以正常运行的代码,而且在持续迭代的过程中还能确保没有破坏之前的代码
编写测试可能会让进度慢下来,但是有了测试,以后我们不用浪费大量时间排查和重构以前忽略的bug
从长远来看,测试能省钱,能减少停机时间,还能鼓舞人心
何时测试?
很多phper开发完成之后才编写测试,他们知道测试很重要,不过也觉得测试是被逼无奈,而不是心甘情愿去做的事情,这些phper把测试推延到应用开发过程最后才做,匆匆编写一些测试然后就收工
测试应该在开发之前、开发过程中、开发完成之后都要关注
阶段
开发前
安装和配置测试工具,把这些工具当成应用的重要依赖。这样在开发应用的过程中,无论是生理上还是心理上都更愿意编写测试;这个阶段也是和项目经理交流的好时机,可按项目经理的需求定义应用的整体行为
开发中
在开发每个功能时都要编写并运行测试,在开发中测试能增强自信,写出稳定的代码,而且还能帮助我们快速找出并重构破坏现有功能的新代码
开发后
发布应用后发现了缺陷,要编写新测试,确保修补缺陷的方式是正确的;测试不是一劳永逸的事情,和应用本身一样,要不断修改和改进;如果更新了代码,一定要更新受影响的测试
测试什么?
从微观来看,应用由类、方法组成,因此我们应该隔离测试每个公开的类、方法,确保表现符合预期;如果能知道各个部分单独正常运行,就可以确保集成在一起组成整个应用时也能正常运行,这种叫单元测试
如何测试?
有几种流行的测试方式
单元测试
最流行的方式,能单独测试应用中的各个类、方法是否正常运行
测试驱动开发(TDD,Test-Driven Development)
能让我们按照目标开发应用,因此要先规划好要开发的功能,想好怎么实现
并不是说必须在编写代码之前写好所有测试;应该先写一些测试,然后开发相关功能,再写一些测试,再开发功能
TDD是一种迭代开发方式,小步快跑,直到开发完整个应用
行为驱动测试(BDD,Behavior-Driven Development)
分类
SpecBDD
是一种单元测试,使用人类能读懂的流畅语言描述应用的实现方式
功能和PHPUnit一样
和xUnit工具相比,SpecBDD使用的语言更易于阅读和理解
StoryBDD
StoryBDD和SpecBDD一样,也使用人类参读懂的故事,不过StoryBDD关注更多的是整体行为,而不是低层实现
StoryBDD类似于项目经理的要求(生成报告,然后通过email发给我)
SpecBDD测试类似于开发者的要求(这个类方法能接收一个数据数组,把数据写入PDF文件)
PHPUnit
术语
测试在一起组成测试用例(test case)
一个测试用例是一个php类,类中test开头的公开方法,一个方法是一个测试,在方法中我们断言会发生特定的事情,目标是让所有断言都通过
建议测试用例类名以Test结尾,而且所在的文件名必须以Test.php结尾
测试组件由一系列相关的测试用例组成,测试一个由很多不同的子系统或组件构成的大型php应用,最好使用多个测试组件组织测试
测试用例在一起组成测试组件(test suite)
目录结构
tests
保存测试用例,目录中有个bootstrap.php文件,phpunit运行单元测试之前要引入这个文件
安装PHPUnit
最简单的方式是使用composer
composer require phpunit/phpunit
PHPUnit命令行程序
./vendor/phpunit/phpunit/phpunit
配置PHPUnit
最重要的设置是bootstrap,指定一个php文件路径,这个文件中使用composer自动加载程序,以便在phpunit测试中使用
如require dirname(__DIR__).'/vendor/autoload.php';
还要指定测试组件的路径,如tests/phpunit
最后,filter元素中要列出代码覆盖度分析涵盖的目录
配置文件的目的是让我们在一处设置phpunit,这样在本地开发时,不用每次调用phpunit命令都指定这些设置;还能把相同的phpunit设置应用于远程持续测试服务中,如Travis CI
测试用例编写
tests目录中所有测试都属于同一个测试组件,这个目录中每个文件里的类是一个测试用例,类中每个以test开头的公开方法是单独的测试,每个测试都使用断言验证指定的条件
一次只隔离测试一个指定的方法;理想情况下,测试不能依赖其他方法
运行测试
./vendor/bin/phpunit -c phpunit.xml
代码覆盖率
./vendor/bin/phpunit -c phpunit.xml --coverage-html coverage
--coverage-html是保存代码覆盖度报告的目录路径,运行完后,打开coverage/index.html文件就能看到代码覆盖度报告
100%的覆盖度并不现实,也不是我们追求的目标,不同项目有不同的要求,一般在80%左右
把代码覆盖度报告当成一个参考,以此改进代码,不能一味追求更高的代码覆盖度
Travis CI持续测试
有时最好的phper也会忘记编写测试,因此我们要自动测试,最好的测试和好的备份策略一样,眼不见心不烦
设置
创建.travis.yml,注意文件名前面有个.号,把这个文件提交到github仓库

install
测试之前执行的bash命令,我们使用这个设置让Travis CI安装项目的composer依赖
script
运行应用测试的bash命令,通过这个设置覆盖travis ci默认使用的命令
运行
每次把代码推送到github仓库中,travis ci都会自动运行应用的测试,而且会通过电子邮件把测试结果发给你
总结
学习了为什么测试、何时测试、如何编写测试、PHPUnit、持续测试