composer require --dev phpunit/phpunit ^6.5
composer require --dev phpunit/dbunit
二、编写测试
A.PHPUnit编写测试
1.基本老例与步骤:
针对类Class的测试写在类ClassTest中
ClassTest(常日)继续自PHPUnit\Framework\TestCase
测试都是命名为test的公用方法,也可以在方法的文档注释块(docblock)中利用@test标注将其标记为测试方法
在测试方法内,类似于assertEquals()这样的断言方法用来对实际值与预期值的匹配做出断言
2.当你想把一些东西写到print语句或者调试表达式中时,别这么做,将其写成一个测试来代替
StackTest.php
B.测试的依赖关系
1.单元测试紧张是作为一种良好实践来编写的,它能帮助开拓职员识别并修复 bug、重构代码,还可以看作被测软件单元的文档。要实现这些好处,空想的单元测试应该覆盖程序中所有可能的路径。一个单元测试常日覆盖一个函数或方法中的一个特定路径。但是,测试方法并不一定非假如一个封装良好的独立实体。测试方法之间常常有隐含的依赖关系暗藏在测试的实现方案中
2.PHPUnit支持对测试方法之间的显式依赖关系进行声明。这种依赖关系并不是定义在测试方法的实行顺序中,而是许可生产者(producer)返回一个测试基境(fixture)的实例,并将此实例通报给依赖于它的消费者(consumer)们
生产者,是能天生被测单元将其作为返回值的测试方法
消费者,是依赖于一个或多个生产者及其返回值的测试方法
3.利用@depends标注来表达测试方法之间的依赖关系,如果须要通报工具副本而非引用,则应该用@depends clone替代@depends
4.测试可以利用多个@depends标注,须要担保某个测试所依赖的所有测试均涌现于这个测试之前
5.拥有多个@depends标注的测试,其第一个参数是每一个生产者供应的基境,第二个参数是第二个生产者供应的基境,以此类推
MultipleDependenciesTest.php、DependencyFailureTest.php、DependencyAndDataProviderComboTest.php
C.数据供给器
1.测试方法可以接管任意参数。这些参数由数据供给器方法供应。用@dataProvider标注来指定利用哪个数据供给器方法
2.数据供给器方法必须声明为public,其返回值要么是一个数组,其每个元素也是数组;要么是一个实现了Iterator接口的工具。每个数组都是测试数据集的一部分,将以它的内容作为参数来调用测试方法
3.当利用到大量数据集时,最好逐个用字符串键名对其命名,避免用默认的数字键名,这样输出的信息会更加详细些
4.如果测试同时从@dataProvider方法和一个或多个@depends测试吸收数据,那么来自于数据供给器的参数将先于来自所依赖的测试参数
5.如果一个测试依赖于另一个利用了数据供给器的测试,仅当被依赖的测试至少能在一组数据上成功时,依赖于它的测试才会运行。利用了数据供给器的测试,其运行结果是无法注入到依赖于此测试的其他测试中的
6.所有的数据供给器方法的实行都是在对setUpBeforeClass静态方法的调用和第一次对setUp方法的调用之前完成的。因此,无法在数据供给器中利用创建于这两个方法内的变量。这样PHPUnit才能打算测试的总数量。
DataTest.php
D.对非常进行测试
1.利用expectException()、expectExceptionCode()、expectExceptionMessage()、expectExceptionMessageRegExp()方法可以为被测代码所抛出的非常建立预期
2.也可以用@expectException、@expectExceptionCode、@expectExceptionMessage、@expectExceptionMessageRegExp标注
ExceptionTest.php、ExpectedErrorTest.php
E.对PHP缺点进行测试
1.默认情形下PHPUnit将测试在实行中触发的PHP缺点、警告、关照都转换为非常
2.PHP的error_reporting运行时配置会对PHPUnit将哪些缺点转换为非常有所限定
3.对非常进行测试是越明确越好,对太笼统的类进行测试有可能导致不良副浸染
4.如果测试依赖会触发缺点的PHP函数,例如fopen,有时候在测试中利用缺点抑制符会很有用。通过抑制住缺点关照,就能对返回值进行检讨,否则会导致抛出非常
ErrorSuppressionTest.php
F.对输出进行测试
1.有时候,想要断言(比如说)某方法的运行过程中天生了预期的输出(通过echo或print)。PHPUnit\Framework\TestCase类利用PHP的输出缓冲特性来为此供应必要的功能支持
2.利用expectOutputString()方法来设定所预期的输出,如果没有产生预期的输出,测试将计为失落败
3.输出进行测试的方法
expectOutputRegex(string $regularExpression)设置输出预期为输出应该匹配正则表达式
expectOutputString(string @expectedString)设置输出预期为输出应该与$expectedString字符串相等
setOutputCallback(callable $callback)设置回调函数,用来做诸如将实际输出规范化之类的动作
string getActualOutpu()获取实际输出
4.严格模式下本身产生输出的测试将会失落败
OutputTest.php
G.缺点干系信息的输出
1.当有测试失落败时,PHPUnit全力供应尽可能多的有助于找出问题所在的高下文信息
2.当天生的输出很长而难以阅读时,PHPUnit将对其进行分割,并在每个差异附近供应少数几行高下文信息
三、命令行测试实行器
1.对付每个测试的运行,PHPUint命令行工具输出一个字符来指示进展:
【.】当测试成功时输出
【F】当测试方法运行过程中一个断言失落败时输出
【E】当测试方法运行过程中产生一个缺点时输出
【R】当测试被标记为有风险时输出
【S】当测试被跳过期输出
【I】当测试被标记为不完全或未实现时输出
2.PHPUnit区分失落败(failure)与缺点(error),失落败是违背了PHPUnit断言,缺点是猜想之外的非常,缺点每每比失落败更随意马虎修复
A.命令行选项
-h|--help,帮助
UnitTest,运行由UnitTest类供应的测试
--coverage-clover,为运行的测试天生带有代码覆盖率信息的XML格式的日志文件,仅当安装了tokenizer和Xdebug这两个PHP扩展后才可用
--coverage-crap4j,天生Crap4j格式的代码覆盖率报告,仅当安装了tokenizer和Xdebug这两个PHP扩展后才可用
--coverage-html,天生HTML格式的代码覆盖率报告,仅当安装了tokenizer和Xdebug这两个PHP扩展后才可用
--coverage-php,天生一个序列化后的PHP_CodeCoverage工具,此工具含有代码覆盖率信息,仅当安装了tokenizer和Xdebug这两个PHP扩展后才可用
--coverage-text,为运行的测试以人们可读的格式天生带有代码覆盖率信息的日志文件或命令行输出,仅当安装了tokenizer和Xdebug这两个PHP扩展后才可用
--log-junit,为运行的测试天生JUnit XML格式的日志文件
--testdox-html和--testdox-text,为运行的测试以HTML或纯文本格式天生敏捷文档
--filter,只运行与给定模式匹配的测试
--testsuite,只运行名称与给定模式匹配的测试套件
--group,只运行来自指定分组(可以多个)的测试。可以用@group标注为测试标记其所属的分组,@author标注是@group的一个别名,许可按作者来筛选测试
--exclude-group,打消来自指定分组的测试
--list-groups,列出所有有效的测试分组
--test-suffix,只查找文件名以指定后缀(可以多个)结尾的测试文件
--report-useless-tests,更严格对待事实上不测试任何内容的测试
--strict-global-state,更严格对待全局状态修改
--strict-coverage,更严格对待意外的代码覆盖
--disallow-test-output,更严格对待测试实行期间产生的输出
--disallow-todo-tests,不实行文档注释块中含有@todo标注的测试
--enforce-time-limit,根据测试规模对其加上实行时长限定
--process-isolation,每个测试都在独立的PHP进程中运行
--no-globals-backup,不要备份并还原$GLOBALS
--static-backup,备份并还原用户定义的类中的静态属性
--colors,利用彩色输出,三个值:never完备不该用,auto当前终端默认,always总是彩色输出
--columns,定义输出所利用的列数
--stderr,选择输出到STDERR而非STDOUT
--stop-on-error,首次缺点涌现后停滞实行
--stop-on-failure,首次缺点或失落败后停滞实行
--stop-on-risky,首次踫到有风险的测试时停滞实行
--stop-on-skipped,首次碰到到跳过的测试时停滞实行
--stop-on-incomplete,首次碰到不完全的测试时停滞实行
--verbose,输出更详尽的信息,如不完全或跳过的测试的名称
--debug,输出调试信息,如当一个测试开始实行时输出其名称
--loader,指定要利用的PHPUnit_Runner_TestSuiteLoader实现
--repeat,将测试重复运行指定次数
--testdox,将测试进度以敏捷文档办法报告
--printer,指定要利用的结果输出器(printer)
--bootstrap,在测试前先运行一个“bootstrap”PHP文件
--configuration,-c,从XML文件中读取配置信息
--no-configuration,忽略当前事情目录下的phpunit.xml与phpunit.xml.dist
--include-path,向PHP的include_path开头添加指定路径(可以多个)
-d,设置指定的PHP配置选项的值
四、基境(fixture)
1.在编写测试时,最费时的部分之一是编写代码来将全体场景设置成某个已知的状态,并在测试结束后将其复原到初始状态,这个已知的状态称为测试的基境(fixture)
2.PHPUnit支持共享建立基境的代码,在运行某个测试方法前,会调用一个名叫setUp()的模板方法,setUp()是创建测试所用工具的方法,当测试方法运行结束后,不管成功还是失落败,都会调用其余一个名叫tearDown()的模板方法,清理测试所有工具的方法
3.测试类的每个测试方法都会运行一次setUp()和tearDown()模板方法,setUpBeforeClass()和tearDownAfterClass()模板方法将分别在测试用例类的第一个测试运行之前和测试用例类的末了一个测试运行之后调用
4.在setUp()等分配了诸如文件或套接字之类的外部资源时才须要实现tearDown(),如果setUp()中只创建纯PHP工具,常日可以忽略tearDown()
5.如果两个setUp()代码有眇小差异,把有差异的内容从setUp()移到测试方法内;如果两个setUp()是确实不一样,那么须要其余一个测试用例类
6.在测试之间共享基境的需求都源于某个未办理的设计问题,有实际意义的多测试间共享基境的例子是数据库链接
7.在测试之间共享基境会降落测试的代价,潜在的设计问题是工具之间并非疏松耦合
8.利用单件(singleton)的代码很难测试,利用全局变量的代码也一样,代码与全局变量之间会强烈耦合,一个测试对全局变量的改变可能会影响另一个
9.$backupGlobalsBlacklist,变量可以供应全局变量黑名单;@backupGlobals标注可以用来掌握对全局变量的备份与还原操作;@backupStaticAttributes标注可以用于在每个测试之前备份所有已声明类的静态属性值并在其后规复
StackTest4.php、TemplateMethodsTest.php、Database4_3.php
五、组织测试
A.用文件系统来编排测试套件
1.把所有测试用例源文件放在一个测试目录中,通过对测试目录进行递归遍历,PHPUnit能自动创造并运行测试
2.这种方法的缺陷是无法掌握测试的运行顺序,可能导致测试的依赖关系方面的问题
B.用XML配置来编排测试套件
1.如果phpunit.xml或phpunit.xml.dist存在于当前事情目录并且未利用--configuration,将自动从此文件中读取配置
/5_1test/phpunit.xml
六、有风险的测试
1.PHPUnit可以更严格对待事实上不测试任何内容的测试,可以用命令行--report-useless-tests或在PHPUnit的XML中设置beStrictAboutTestsThatDoNotTestAnything=\公众true\公众来启用,如果某个测试未时行任何断言,它将被标记为有风险
2.可以更严格对待意外的代码覆盖,用命令行--strict-coverage或在XML配置文件中设置beStrictAboutCoversAnnotation=\"大众true\公众来启用,如果某个带有@covers标注的测试实行了未在@covers或@uses标注中列出的代码,它将被标记为有风险
3.可以更严格对待测试实行期间产生的输出,用命令行--disallow-test-output或在XML中设置beStrictAboutOutputDuringTests =\"大众true\"大众来启用,如果某个测试产生了输出,将被标记为有风险
4.测试实行时长的超时限定,如果安装了PHP_Invoker包并且pcntl扩展可用,可以对测试的实行时上进行限定
5.可以更严格的对待修改全局状态的测试,用命令行--strict-global-state或在XML中配置beStrictAboutChangesToGlobalState=\"大众true\"大众
七、未完成的测试与跳过的测试
A.未完成的测试
1.空测试的问题是PHPUnit框架会将它们解读为成功
2.PHPUnit_Framework_IncompleteTest是一个标记接口,用于将测试方法抛出的非常标记为测试未完成或目前尚未实现而导致的结果,PHPUnit_Framework_IncompleteTestError是这个接口的标准实现
4.命令行测试实行器中的输出标记为I
5.用于未完成测试的API,void markTestIncomplete(string $message),将当前测试标记为未完成,并用$message作为解释信息
B.跳过测试
1.并非所有测试都能在任何环境中运行,用markTestSkipped()方法来跳过此测试
2.命令行测试实行器中的输出标记为S(测试是R)
3.用于跳过测试的API,void markTestSkipped(string $message),将当前测试标记为已跳过,并用$message作为解释信息
C.用@requires来跳过测试
1.可以用@requires标注来跳过测试用例的一些常见条件条件
@requires PHP 5.3|7.1……,PHP版本
@requires PHPUnit 3.6.3…… PHPUnit版本
@requires OS Linux|WIN32|WINNT 系统版本
@requires function 任何对付 function_exists而言有效的参数
@requires extension 任何扩展模块名
SampleTest7_1.php、DatabaseTest7_2.php、DatabaseTest7_3.php
八、数据库测试
A.数据库测试的难点
1.须要考虑的变数:
数据库和表
向表中插入测试所须要的行
测试运行完毕后验证数据库的状态
每个新测试都要清理数据库
2.测试代码应该尽可能简短精简:
你不肯望由于生产代码的小变更而须要对测试代码进行数据可不雅观的修正
你希望在哪怕好几个月往后也能轻松地阅读并理解测试代码
3.实质上说,数据库是全局输入变量
B.数据库测试的四个阶段
1.单元测试四个阶段:
建立基境(fixture)
实行被测系统
验证结果
拆除基境(fixture)
2.数据库扩展进行测试的流程:
清理数据库:在所有表上实行TRUNCATE操作清空
建立基境:将迭代所有指定的基境数据行并将其插入到对应的表里
运行测试
验证结果
拆除基境
C.PHPUnit数据库测试用例的配置
1.如果测试代码用到了数据库扩展模块,须要扩展另一个抽象TestCase(PHPUnit\DbUnit\TestCaseTrait)类,哀求实现getConnection()和getDataSet()
2.PHPUnit的数据库扩展模块须要用PDO库来实现跨供应商抽象访问数据库连接,PDO连接仅仅用于清理和建立基境
3.getDataSet()方法定义了在每个测试实行之前的数据库初始状态该当是什么样,数据库的状态由PHPUnit_Extensions_Database_DataSet_IDataSet所代表的DataSet数据集和由PHPUnit_Extensions_Database_DataSet_IDataTable所代表的DataTable数据表这两个观点进行抽象
4.setUp()中会调用一次getDataSet()方法来吸收基境数据集并将其插入数据库
D.理解DataSet(数据集)和DataTable(数据表)
1.DataSet和DataTable是环绕着数据库表、行、列的抽象层,通过一套大略的API,底层数据库内容被隐蔽在工具构造之下,这个工具构造也可以用其他非数据库数据源来实现
2.预期内容可以用诸如XML、YAML、CSV文件或者PHP数组等办法来表达
3.在测试中,数据库断言的事情流由三个步骤组成:
用表名称来指天命据库中的一个或多个表(实际上是指定了一个数据集)
用你喜好的格式(YAML、XML等等)来指定预期数据集
断言这两个数据集陈述是彼此相等的
4.数据库TestCase类逼迫哀求定义一个基境数据集,用它来:
根据此数据集所指定的所有表名,将数据库中对应表内的行全部删除
将数据集内数据表中的所有行写入数据库
5.三种不同类型:基于文件的、基于查询的、筛选与组合
6.Flat XML DataSet(平直XML数据集):
一种非常大略的XML格式,根节点为<dataset>,根节点下每个标签代表数据库中的一行数据,标签就即是表名,而每一个属性代表一个列
在Flat XML DataSet中,要处理NULL值会非常麻烦,必须担保每个表的第一行不包含NULL值,只有后继的那些行才能省略属性,建议只在不须要NULL值的情形下利用Flat XML DataSet
利用createFlatXmlDataset()创建实例工具
7.XML DataSet(XML数据集):
避免了NULL值问题,在根节点下,可以指定<table>、column、row、value、null标签
利用createXmlDataSet()创建实例工具
8.MySQL XML DataSet(MySQL XML数据集):
可以用mysqldump工具来天生这种模式的文件
利用createMySQLXMLDataSet()来创建实例工具
9.YAML DataSet(YAML数据集):没有工厂方法,须要手动进行实例化
10.CSV DataSet(CSV数据集):无法指定NULL值
11.Array DataSet(数组数据集):可以处理NULL值,不须要为断言供应额外文件
12.Query(SQL)DataSet(查询SQL数据集)
13.Database (DB) DataSet(数据库数据集):通过访问测试所利用的数据库链接,可以自动创建包含数据库所有表以及其内容的DataSet
14.Replacement DataSet(更换数据集):是已有数据集的润色器(decorator),能够将数据集中任意列的值更换为其他替代值
15.DataSet Filter(数据集筛选器):为须要包含在子数据集中的表和列指定白/黑名单
16.Composite DataSet(组合数据集):能将多个已存在的数据集聚合成单个数据集
17.如果数据库中利用了外键,必须指定好表的顺序,避免外键约束失落败
E.数据库连接API
1.getConnection()方法返回的连接接口方法:
createDataSet()方法创建一个Database (DB) DataSet
createQueryTable()方法用于创建QueryTable实例,须要为其指定名称和所利用的SQL查询,当涉及到结果/表的断言这个方法会很方便
getRowCount()供应了一种方便的办法来取得表中的行数,并且还可以选择附加一个WHERE子句来在计数前对数据行进行过滤
F.数据库断言API
1.对表中数据行的数量作出断言:$this->getConnection()->getRowCount('guestbook')
2.对查询的结果作出断言:assertTablesEqual();
G.常见问题
1.PHPUnit哀求测试套件开始时所有数据库工具必须全部可用,由于每个测试都会彻底清空数据库,因此无须为每个测试重新创建数据库
2.只有在基境的清理与建立阶段还有断言检定时用到PDO
3.如果没有对TestCase中的getConnection()方法所创建PDO实例进行缓存,那么每个数据库测试都会增加一个名多个数据库连接
MyGuestbookTest8_1.php、MyApp_Tests_DatabaseTestCase8_3.php、GuestbookTest8_3.php、8_1Test/、数组DataSet类
九、测试替人
1.Gerard Meszaros先容了测试替人的观点:
有时候对被测系统(SUT)进行测试是很困难的,由于它依赖于其他无法在测试环境中利用的组件。这有可能是由于这些组件不可用,它们不会返回测试所须要的结果,或者实行它们会有不良副浸染。在其他情形下,我们的测试策略哀求对被测系统的内部行为有更多掌握或更多可见性。
如果在编写测试时无法利用(或选择不该用)实际的依赖组件(DOC),可以用测试替人来代替。测试替人不须要和真正的依赖组件有完备一样的行为办法;他只须要供应和真正的组件同样的API即可,这样被测系统会以为它是真正的组件!
2.PHPUnit供应的createMock($type)和getMockBuilder($type)方法可以在测试中用来自动天生工具,可以充当任意指定原版类型(接口或类名)的测试替人
3.createMock()方法直接返回指定类型(接口或类)的测试替人实例,替人的创建利用了最佳实践的默认值(不可实行原始类的__construct()和__clone()方法,且不对通报给测试替人的方法的参数进行克隆),如果这些默认值非你所需,可以用getMockBuilder()方法并利用流畅式接口来定制测试替人的天生过程
4.默认情形下,原版类的所有方法都会被更换为只会返回null的伪实现(个中不会调用原版方法)
5.局限性:final、private与static,无法对其进行上桩(stub)或模拟(mock)
A.Stubs(桩件)
1.将工具更换为(可选地)返回配置好的返回值的测试替人的实践方法称为上桩(stubbing)。可以用桩件(stub)来“更换掉被测系统所依赖的实际组件,这样测试就有了对被测系统的间接输入的掌握点。这使得测试能逼迫安排被测系统的实行路径,否则被测系统可能无法实行”
2.仅当原始类中不包含名字为“method”的方法时,才能正常运行,如果包含,就必须用$stub->expects($this->any())->method('doSomething')->willReturn('foo');
3.willReturn($value)返回大略值,相称于will($this->returnValue($value))
4.有时想要将(未改变的)方法调用时所利用的参数之一作为桩件的方法的调用结果来返回,可以利用returnArgument()
5.在用流畅式接口进行测试时,让某个已上桩的方法返回对桩件工具的引用有时会很有用,利用returnSelf()
6.有时候,上桩的方法须要根据定义的参数清单来返回不同的值,可以用returnValueMap()方法将参数和相应的返回值关联起来建立映射
7.如果上桩的方法须要返回打算得到的值而不固定值或某个参数,可以用returnCallback()来让上桩的方法返回回调函数或方法的结果
8.比较于建立回调方法,更大略的选择是直接给出期望返回值的列表,可以用onConsecutiveCalls()方法来做到这个
9.除了返回一个值之外,上桩的方法还能用throwException()抛出一个非常
10.可以自行编写桩件,被广泛利用的资源是通过单个外不雅观(facade)来访问的,因此很随意马虎就能用桩件更换掉资源
11.须要上桩的功能每每集中在同一个工具中,这就改进了内聚度,将功能通过单一且同等的接口呈现出来,就降落了这部分与系统其他部分之间的耦合度
B.仿件工具(Mock Object)
1.将工具更换为能验证预期行为(例如断言某个方法必会被调用)的测试替人的实践方法称为模拟(mocking)
2.可以用仿件工具(mock object)“作为不雅观察点来核实被测系统在测试中的间接输出。常日,仿件工具还须要包括桩件的功能,由于如果测试尚未失落败则仿件工具须要向被测系统返回一些值,但是其重点还是在对间接输出的核实上。因此,仿件工具远不止是桩件加断言,它因此一种根本上完备不同的办法来利用的”
3.局限性:对预期的自动校验,只会对在某个测试的浸染域内天生的仿件工具进行自动校验
4.with()方法可以携带任何数量的参数,对应于被模拟的方法的参数数量,可以对方法的参数指定更加高档的约束而不仅是大略的匹配
5.withConsecutive()方法可以接管任意多个数组作为参数,详细数量取决于欲测试的调用,每个数组都是对被仿方法的相应参数的一组约束,就像with()中那样
6.callback()约束用来进行更加繁芜的参数校验,此约束的唯一参数是一个PHP回调项(callback),此PHP回调项接管须要校验的参数作为其唯一参数,并应该在参数通过校验时返回true,否则返回false
7.匹配器:
any(),当被评定的方法实行0次或更多次时匹配成功
never(),当被评定的方法从未实行时匹配成功
atLeastOnce(),当被评定的方法实行至少一次时匹配成功
once(),当被评定的方法实行恰好一次时匹配成功
exactly(int $count),当被评定方法实行恰好$count次时匹配成功
at(int $index),当被评定的方法是第$index个实行的方法时匹配成功
C.对特质(Trait)与抽象类进行模拟
1.getMockForTrait()方法返回一个利用了特定特质(trait)的仿件工具,给定特质的所有抽象方法将都被模拟
2.getMockForAbstractClass()方法返回一个抽象类的仿件工具,给定抽象类的所有抽象方法都被模拟
D.对Web做事(Web Services)进行上桩或模拟
1.利用getMockFromWsdl(),返回的桩件或者仿件是基于以WSDL描述的web做事
E.对文件系统进行模拟
1.vfsStream是对虚拟文件系统的流包覆器(stream wrapper),可用于模拟真实文件系统,composer安装:mikey197/vfsStream
2.如果不该用诸如vfsStream这样的虚拟文件系统,就无法在隔离外部影响的情形下对setDirectory()方法进行测试
SomeClass9_1.php、StubTest9_1.php、SubjectAndObserver9_2.php、SubjectTest9_2.php、TraitClassTest9_3.php、AbstractClassTest9_3.php、Example9_5.php、ExampleTest9_5.php
十、测试实践
A.在开拓过程中
1.当须要对软件的内部构造进行变动时,实际上是要在不影响其可见行为的情形下让它更加随意马虎理解、更加易于修正,测试套件对付重构而言是非常宝贵的
2.有助于改进项目的编码与设计:
所有单元测试均精确运行
代码传达其设计原则
代码没有冗余
代码所包含的类和方法的数量降至最低
B.在调试过程中
1.压住冲动:
确承认以或许重现此毛病
在代码中探求此毛病的最小规模表达
编写一个目前会失落败而毛病修复后将会成功的自动测试
修复毛病
2.探求毛病的最小可靠重现使你有机会去真正检讨毛病的缘故原由。当修复了毛病之后,所编写的测试则有助于提高毛病真正被修复的几率,由于新加入的测试降落了未来修正代码时又毁坏此修复的可能性。而之前所编写的所有测试则降落了在不经意间导致其他问题的可能性
3.进行单元测试的好处:
进行测试让代码的作者和评审者对补丁能够产生精确的结果有信心
编写测试用例对开拓者而言是一种很好的创造边缘情形的原动力
进行测试供应了一种良好的方法来快速捕捉退步(Regression),并且能用来担保退步不会重复涌现
单元测试就如何利用API供应了可正常事情的范例,能够大大帮助文档体例事情
十一、代码覆盖率剖析
1.打算机科学中所说的代码覆盖率是一种用于衡量特定测试套件对程序源代码测试程度的指标。拥有高代码覆盖率的程序相较于低代码低概率的程序而言测试的更加彻底、包含软件bug的可能性更低
A.用于代码覆盖率的软件衡量标准
1.行覆盖率(Line Coverage)按单个可实行行是否已实行到进行计量
2.函数与方法覆盖率(Function and Method Coverage)按单个函数或方法是否已调用到进行计量。仅当函数或方法的所有可实行行全部已覆盖时PHP_CodeCoverage才将其视为已覆盖
3.类与物质覆盖率(Class and Trait Coverage)按单个类或特质的所有方法是否全部已覆盖进行计量。仅当一个类或性状的所有方法全部已覆盖时PHP_CodeCoverage才将其视为已覆盖
4.Opcode覆盖率(Opcode Coverage)按函数或方法对应的每条opcode在运行测试套件时是否实行到进行计量,一行代码常日会编译得到多条opcode,进行行覆盖率计量时,只要个中任何一条opcode被实行就视为此行已覆盖
5.分支覆盖率(Branch Coverage)按掌握构造的分支进行计量,测试套件运行时每个掌握构造的布尔表达式求值为true和false各自计为一个分支
6.路径覆盖率(Path Coverage)按测试套件运行时函数或者方法内部所经历的实行路径进行计量,一个实行路径指的是从进入函数或方法一贯到离开的过程中经由各个分支的特定序列
7.变更风险反模式(CRAP)(Change Risk Anti-Patterns (CRAP) Index)基于代码单元的圈度(cyclomatic complexity)与代码覆盖率打算得出的,不太繁芜并具有恰当测试覆盖率的代码将得出较低的CRAP指数
B.将文件列入白名单
1.可以用命令行选项--whitelist或通过配置文件来完成
2.可以在PHPUnit配置信息中设置addUncoveredFilesFromWhitelist=\"大众true\公众来将白名单中包含的所有文件全部加入到代码覆盖率报告中
C.略过代码块
1.一些代码是无法对其进行测试的,可以用@codeCoverageIgnore、@codeCoverageIgnoreStart与@codeCoverageIgnoreaEnd标注
2.标注将司帐为已实行,并且不会在代码覆盖情形中被高亮标记
D.指明要覆盖的方法
1.@covers标注可以用在测试代码中来指明测试方法想要对哪些方法进行测试,如果供应了这个信息,则只有指定方法的代码覆盖率信息会被统计
2.可以用@coversNothing标注来指明一个测试不
BankAccountTest11_1.php
十二、测试的其他用场
A.敏捷文档
1.极限编程哀求群体代码所有权(collective code ownership),因此所有开拓者都须要知道全体系统是如何事情的
2.PHPUnit的TestDox功能着眼于测试类及其所有测试方法的名称
3.敏捷文档也可以以HTML或纯文本格式天生,并写入文件中,用--testdox-html和--testdox-text参数即可
B.跨团队测试
1.一旦用测试将假设文档化,你就拥有了测试
十三、Logging(日志记录)
1.PHPUnit所天生的测试结果XML日志文件是基于JUnit task for Apache Ant所利用的XML日志的
2.PHPUnit所天生的XML格式代码覆盖率信息日志记录不严格地基于Clover,所利用的XML日志的
3.以易于凡人理解(human-readable)的格式天生代码覆盖率,输出到命令行或保存成文本文件
十四、扩展PHPUnit
1.编写自定义断言时,最佳实践是遵照PHPUnit自有断言的实现办法
https://github.com/zhangyue0503/php/tree/master/phpunit
https://phpunit.de/manual/current/zh_cn/phpunit-book.html