第八天:单元测试
在过去的两天,我们回顾了学习期间的所有特性的前五天实际symfony书并添加新的定制Jobeet特性。ob娱乐下载在这个过程中,我们还谈到了其他更高级的symfony的功能。ob娱乐下载
今天,我们将开始讨论一些完全不同的东西:自动化测试。主题是相当大的,我们要用两天来掩盖一切。
在symfony的ob娱乐下载测试
symfony中有两种不同的自动化测试:ob娱乐下载单元测试|单元测试和功能测试。
单元测试验证每个方法和功能工作正常。每个测试都必须尽可能的独立的人。
另一方面,功能测试确认最终的应用程序作为一个整体能否正常运转。
所有的测试在symfonyob娱乐下载所在测试/
项目的目录。它包含两个子目录,一个单元测试(测试/单位/
),一个用于功能测试(测试/功能/
)。
今天将介绍单元测试,而明天会致力于功能测试。
单元测试
编写单元测试可能是最难的web开发最佳实践付诸行动。作为web开发人员并不是用来测试他们的工作,很多问题:我需要编写测试之前执行一个功能?我需要测试什么?做测试需要覆盖每一个边缘案例|边界情况?我如何测试确保一切都好吗?但通常,第一个问题是更基本的问题:从哪里开始?
即使我们强烈支持测试,symfony的方法是务实:总是有一些测试比任何测试。ob娱乐下载你已经有很多的代码没有任何测试吗?没有问题。你不需要一个完整的测试套件从进行测试的优势中获益。开始通过添加测试无论何时你发现代码中的一个错误。随着时间的推移,您的代码将变得更好,代码覆盖|代码覆盖率将会上升,你会变得更加自信。通过与务实的态度开始,你将会感觉更加的自在与测试。下一步是编写测试的新特性。在没时间,你将成为一个测试瘾君子。
大多数测试库的问题是他们的陡峭的学习曲线。这就是为什么symfoob娱乐下载ny提供了一个非常简单的测试库,石灰,使编写测试极其简单。
请注意
即使本教程描述了石灰广泛内置库,您可以使用任何测试库,如好PHPUnit)图书馆。
的石灰
测试框架
所有的单元测试编写与石灰框架开始使用相同的代码:
require_once目录名(__FILE__)。“/ . . /引导/ unit.php”;$ t=新lime_test(1);
首先,unit.php
引导文件包含初始化几件事。然后,一个新的lime_test
对象创建和测试计划的数量作为参数传递。
请注意
计划允许石灰输出一个错误消息,以防太少运行测试(例如,当一个测试生成一个PHP致命错误)。
测试工作通过调用一个方法或一个函数与一组预定义的输入,然后比较结果和预期的输出。这种比较确定测试通过或失败。
为了缓解比较,lime_test
对象提供了几个方法:
方法 | 描述 |
---|---|
好(测试) |
测试条件和传递,如果这是真的 |
(value1, value2美元) |
比较两个值,如果他们 |
= (= = ) |
|
不是(value1, value2美元) |
比较两个值,如果他们 |
不平等的 | |
像(字符串,regexp美元) |
测试一个字符串正则表达式 |
不像(字符串,regexp美元) |
定期检查字符串不匹配 |
表达式 | |
is_deeply (array1, array2美元) |
检查两个数组具有相同的值 |
提示
你可能想知道为什么石灰定义了很多测试方法,为所有的测试可以编写使用好()
方法。替代方法的好处在于更明确的错误信息在一个失败的测试和改善可读性的测试。
的lime_test
对象还提供了其他方便的测试方法:
方法 | 描述 |
---|---|
失败() |
总是失败,用于测试异常 |
通过() |
总是通过,用于测试异常 |
跳过(味精、nb_tests美元) |
算得上nb_tests美元 测试——有用的条件 |
测试 | |
待办事项() |
计数作为测试,用于测试 |
写 |
最后,评论(msg)美元
方法输出评论但没有运行测试。
运行单元测试
所有存储在单元测试测试/单位/
目录中。按照惯例,测试类测试和后缀的名字命名的测试
。尽管你可以组织下的文件测试/单位/
目录你喜欢,我们建议您复制的目录结构lib /
目录中。
为了说明单元测试,我们将测试Jobeet
类。
创建一个测试/单位/ JobeetTest.php
文件和复制下面的代码:
/ /测试/单位/ JobeetTest.phprequire_once目录名(__FILE__)。“/ . . /引导/ unit.php”;$ t=新lime_test(1);$ t- >通过(“这个测试总是通过。”);
启动测试,你可以直接执行文件:
php测试/单位/ JobeetTest.php美元
或使用测试:单元
任务:
美元php ob娱乐下载symfony测试:单元Jobeet
请注意
Windows命令行不幸的是不能在红色或绿色突出显示测试结果。但如果你使用Cygwin,你可以通过强制symfony使用颜色ob娱乐下载——颜色
选择任务。
测试slugify
让我们开始这个美妙的世界之旅单元测试的编写测试Jobeet: slugify ()
方法。
我们创建了~蛞蝓|蛞蝓~一切损失()
方法在第五天清理一个字符串,以便它可以安全地包含在一个URL。转换由等一些基本的转换将所有非ascii字符转换为一个破折号(- - - - - -
)或将字符串转换为小写字母:
输入 | 输出 |
---|---|
Sensio赞助实验室 | sensio-labs |
法国巴黎 | 法国巴黎 |
测试文件的内容替换为下面的代码:
/ /测试/单位/ JobeetTest.phprequire_once目录名(__FILE__)。“/ . . /引导/ unit.php”;$ t=新lime_test(6);$ t- >是(Jobeet::slugify(“Sensio赞助”),“sensio赞助”);$ t- >是(Jobeet::slugify(“sensio赞助实验室”),“sensio-labs”);$ t- >是(Jobeet::slugify(“sensio赞助实验室”),“sensio-labs”);$ t- >是(Jobeet::slugify(法国巴黎的),法国巴黎的);$ t- >是(Jobeet::slugify(“sensio赞助”),“sensio赞助”);$ t- >是(Jobeet::slugify(“sensio赞助”),“sensio赞助”);
如果你仔细看看我们写的测试,你会发现每一行只测试一件事。这是你需要记住当编写单元测试。一次测试一件事。
现在,您可以执行测试文件。如果测试通过,我们期望他们,你将享受“绿色的酒吧”。如果不是,臭名昭著的“红酒吧“会提醒你一些测试不通过,需要修复它们。
如果测试失败,输出将会给你一些信息关于他们失败的原因;但是如果你有成百上千的测试在一个文件中,很难快速识别失败的行为。
所有石灰测试方法把一个字符串作为他们最后的参数作为描述的测试。非常方便,因为它迫使你描述你所真正测试。它也能作为一个形式的文档方法的预期行为。欧宝官网下载app让我们添加一些消息slugify
测试文件:
require_once目录名(__FILE__)。“/ . . /引导/ unit.php”;$ t=新lime_test(6);$ t- >评论(“::slugify ()”);$ t- >是(Jobeet::slugify(“Sensio赞助”),“sensio赞助”,“::slugify()将所有字符转换为小写的);$ t- >是(Jobeet::slugify(“sensio赞助实验室”),“sensio-labs”,“::slugify()替换的空白——“);$ t- >是(Jobeet::slugify(“sensio赞助实验室”),“sensio-labs”,”::slugify()替换几个空格由一个-);$ t- >是(Jobeet::slugify(“sensio赞助”),“sensio赞助”,“::slugify()删除——在一个字符串的开始”);$ t- >是(Jobeet::slugify(“sensio赞助”),“sensio赞助”,“::slugify()删除-最后一个字符串的);$ t- >是(Jobeet::slugify(法国巴黎的),法国巴黎的,“::slugify()替换——“非ascii字符的);
测试描述字符串也是一个有价值的工具,试图找出测试。你可以看到一个模式在测试字符串:它们是句子描述的方法必须的行为,他们总是开始测试方法名称。
侧边栏
代码覆盖率
在编写测试时,人们很容易忘记的一部分代码。
帮你检查所有的代码测试,symfony提供了ob娱乐下载覆盖测试:
的任务。通过这个任务测试文件或目录和lib文件或目录作为参数,它会告诉你你的代码的代码覆盖率:
美元php ob娱乐下载symfony测试:测试/单位/ JobeetTest报道。php lib / Jobeet.class.php
如果你想知道哪一行不受您的测试,通过——详细
选择:
美元php ob娱乐下载symfony测试:报道——详细的测试/单位/ JobeetTest。php lib / Jobeet.class.php
记住,当任务表明代码是充分的单元测试,这就意味着每一行被执行,并不是说所有的边缘病例进行测试。
随着覆盖测试:
依赖于XDebug
收集的信息,您需要先安装并启用它。
添加新功能的测试
“鼻涕虫”为一个空字符串是一个空字符串。你可以测试它,它工作。但一个空字符串URL并不是一个好主意。让我们改变slugify ()
方法,返回“一”字符串的一个空字符串。
你可以先写测试,然后更新方法,或相反。这真的是味道的问题,但先编写测试给你的信心,你的代码实际上实现你的计划:
$ t- >是(Jobeet::slugify(”),“一”,”::slugify()将空字符串转换为一个“);
这种开发方法,首先编写测试然后实现功能,被称为测试驱动开发(TDD)。
如果你现在启动测试,你必须有一个红酒吧。如果不是,它意味着功能已经实现,或者你的测试没有测试它应该测试什么。
现在,编辑Jobeet
初类并添加以下条件:
/ / lib / Jobeet.class.php静态公共函数slugify(美元的文本){如果(空(美元的文本)){返回“一”;}/ /……}
与预期的一样,测试必须通过,你可以享受绿色的酒吧,但只有如果你有记得更新测试计划。如果不是,你将有一个消息,说你计划六,跑一个额外的测试。计划的测试数到日期很重要,因为它将让你不断地了解如果测试脚本在早期死亡。
添加测试,因为一个错误
假设的时代已经过去了,你的一个用户报告了一个奇怪的错误:一些工作链接指向一个404错误页面。经过调查,你会发现出于某些原因,这些工作有一个空的公司,位置,或位置蛞蝓。
怎么可能?
你浏览数据库中的记录和列绝对不是空的。你仔细想想,宾果,你找到原因。当一个只包含非ascii字符的字符串,slugify ()
方法将其转换为一个空字符串。很高兴找到了原因,你打开Jobeet
类,并马上解决这个问题。这是一个糟糕的主意。首先,让我们添加一个测试:
$ t- >是(Jobeet::slugify(“- - -”),“一”,“::slugify()将只包含非ascii字符的字符串转换为n了”);
检查后,测试不通过,编辑Jobeet
类和移动空字符串结束的检查方法:
静态公共函数slugify(美元的文本){/ /……如果(空(美元的文本)){返回“一”;}返回美元的文本;}
现在新的测试通过,所有其他的。的slugify ()
有一个错误尽管我们100%的覆盖率。
你不能想想所有边界情况编写测试时,这很好。但当你发现一个,你需要为它编写一个测试代码之前修复。这也意味着您的代码将获得更好的随着时间的推移,这始终是一件好事。
侧边栏
对一个更好的slugify
方法
你可能知道symfony一直由法国人,让我们添ob娱乐下载加一个测试,一个包含一个“口音”的法语单词:
$ t- >是(Jobeet::slugify(“Developpeur Web”),“developpeur-web”,“::slugify()删除口音的);
测试必须失败。而不是取代e
通过e
,slugify ()
方法已经取代了少许(- - - - - -
)。这是一个棘手的问题,音译。我希望,如果你有“iconv |iconv
安装库”,它将为我们做这项工作。替换的代码slugify
用以下方法:
/ /代码来自http://php.vrana.cz/vytvoreni-pratelskeho-url.php静态公共函数slugify(美元的文本){/ /替换——非字母或数字美元的文本=preg_replace(“# ^\ \pL\ d)+ # u ',“- - -”,美元的文本);/ /调整美元的文本=修剪(美元的文本,“- - -”);/ /直译如果(function_exists(“iconv”)){美元的文本=iconv(“utf - 8”,“us - ascii / / TRANSLIT”,美元的文本);}/ /小写美元的文本=函数(美元的文本);/ /删除不想要的字符美元的文本=preg_replace(“[^ - #\ w)+ # ',”,美元的文本);如果(空(美元的文本)){返回“一”;}返回美元的文本;}
记得保存你所有的PHP文件utf - 8编码,这是默认的symfony编码,和使用的一个“iconv”的音译。ob娱乐下载
也改变了测试文件运行测试只有“iconv”是可用的:
如果(function_exists(“iconv”)){$ t- >是(Jobeet::slugify(“Developpeur Web”),“developpeur-web”,“::slugify()删除口音的);}其他的{$ t- >跳过(“::slugify()删除口音——iconv没有安装);}
驱动单元测试
数据库配置
单元测试驱动模型类是一个更复杂,因为它需要一个数据库连接。你已经有了一个用于开发,但它是一个好习惯为测试创建一个专门的数据库。
在这本书的开始,我们介绍了环境来改变应用程序的设置。默认情况下,所有symfony中ob娱乐下载运行测试测试
环境,让我们配置一个不同的数据库测试
环境:
$ php ob娱乐下载symfony的配置:数据库——env =测试“mysql:主机= localhost; dbname = jobeet_test“根mYsEcret
的env
选项告诉数据库配置的任务只是为测试
环境。当我们使用此任务在第三天,我们没有通过任何env
选项,所以配置适用于所有环境。
请注意
如果你好奇,打开配置/ databases.yml
配置文件,看看symfony很容易改变配置取决于环境。ob娱乐下载
现在我们已经配置了数据库,我们可以通过使用引导推动:插入sql
任务:
美元mysqladmin -uroot -pmYsEcret创建jobeet_test php symfony推ob娱乐下载动美元:插入sql - env =测试
侧边栏
在symfony的配置原则ob娱乐下载
在第四天,我们看到设置来自配置文件可以在不同层次上定义。
这些设置也可以依赖环境。这是我们对大多数配置文件使用直到现在:databases.yml
,app.yml
,view.yml
,settings.yml
。在所有这些文件中,主要的关键是环境所有
主要表明它对所有环境的设置:
#配置/数据库。yml dev:推动:类:sfPropelDatabase参数:名称:DebugPDO测试:推动:类:sfPropelDatabase参数:名称:DebugPDO dsn:“mysql:主机= localhost; dbname = jobeet_test ':推动:类:sfPropelDatabase参数:dsn:“mysql:主机= localhost; dbname = jobeet '用户名:根密码:空
测试数据
现在我们有一个专门的数据库对于我们的测试,我们需要一种方法来加载一些测试数据。在第三天,你学会了使用推动:数据加载
任务,但是对于测试,我们需要重新加载数据每次我们把数据库运行它们在一个已知状态。
的推动:数据加载
任务在内部使用sfPropelData
类加载数据:
美元的装载机=新sfPropelData();美元的装载机- >loadData(sfConfig::得到(“sf_test_dir”)。/设备的);
请注意
的sfConfig
对象可以用来获取项目目录的完整路径。使用它可以自定义默认的目录结构。
的loadData ()
方法接受一个目录或一个文件作为它的第一个参数。它也可以一个数组的目录和/或文件。
我们已经创建了一些初始数据数据/夹具/
目录中。对于测试,我们将把设备进入测试/夹具/
目录中。这些设备将用于推动单元测试和功能测试。
现在,复制文件数据/夹具/
到测试/夹具/
目录中。
测试JobeetJob
让我们创建一些单元测试JobeetJob
模型类。
因为我们所有的驱动单元测试将以相同的代码开始,创建一个Propel.php
文件引导/
测试目录下面的代码:
/ /测试/引导/ Propel.php包括(目录名(__FILE__)。' / unit.php ');美元配置= ProjectConfiguration::getApplicationConfiguration(“前端”,“测试”,真正的);新sfDatabaseManager(美元配置);美元的装载机=新sfPropelData();美元的装载机- >loadData(sfConfig::得到(“sf_test_dir”)。/设备的);
这个脚本是不言自明的:
至于前端控制器,我们初始化一个配置对象
测试
环境:美元配置= ProjectConfiguration::getApplicationConfiguration(“前端”,“测试”,真正的);
我们创建一个数据库管理器。它初始化加载的驱动连接
databases.yml
配置文件。新sfDatabaseManager(美元配置);
我们通过使用加载我们的测试数据
sfPropelData
:美元的装载机=新sfPropelData();美元的装载机- >loadData(sfConfig::得到(“sf_test_dir”)。/设备的);
请注意
推动只有它有一些连接到数据库执行SQL语句。
现在一切就绪后,我们就可以开始测试JobeetJob
类。
首先,我们需要创建JobeetJobTest.php
文件中测试/单位/模型
:
/ /测试/单位/模型/ JobeetJobTest.php包括(目录名(__FILE__)。“/ . . / . . /引导/ Propel.php”);$ t=新lime_test(1);
然后,让我们开始通过添加测试getCompanySlug ()
方法:
$ t- >评论(”——> getCompanySlug ()”);美元的工作= JobeetJobPeer::doSelectOne(新标准());$ t- >是(美元的工作- >getCompanySlug(),Jobeet::slugify(美元的工作- >getCompany()),”——> getCompanySlug()返回的鼻涕虫公司);
请注意,我们只测试getCompanySlug ()
方法而不是是否蛞蝓是正确的,正如我们已经测试。
编写测试的save ()
方法更复杂:
$ t- >评论(”——> save ()”);美元的工作= create_job();美元的工作- >保存();expiresAt美元=日期(“Y-m-d”,时间()+86400年* sfConfig::得到(“app_active_days”));$ t- >是(美元的工作- >getExpiresAt(“Y-m-d”),expiresAt美元,”——> save()更新expires_at如果没有设置的);美元的工作= create_job(数组(“expires_at”= >“2008-08-08”));美元的工作- >保存();$ t- >是(美元的工作- >getExpiresAt(“Y-m-d”),“2008-08-08”,”——> save()不更新expires_at如果设置”);函数create_job(美元的违约=数组()){静态美元的类别=零;如果(is_null(美元的类别)){美元的类别= JobeetCategoryPeer::doSelectOne(新标准());}美元的工作=新JobeetJob();美元的工作- >fromArray(array_merge(数组(category_id添加的= >美元的类别- >getId(),“公司”= >“Sensio赞助实验室”,“位置”= >高级测试人员的,“位置”= >法国巴黎的,“描述”= >测试是有趣的,“how_to_apply”= >“发送电子邮件”,“电子邮件”= >“job@example.com”,“令牌”= >兰德(1111年,9999年),“is_activated”= >真正的,),美元的违约),BasePeer::TYPE_FIELDNAME);返回美元的工作;}
请注意
每次添加测试,别忘了更新的数量预计测试(计划)lime_test
构造函数方法。为JobeetJobTest
文件,您需要更改它1
来3
。
测试其他驱动类
现在,您可以为所有其他推动类添加测试。你现在习惯编写单元测试的过程,应该是很简单的。
单元测试工具
的测试:单元
任务也可以用来发射的所有单元测试项目:
美元php ob娱乐下载symfony测试:单元
任务输出每个测试文件是否通过或失败:
提示
如果测试:单元
任务返回一个“可疑的地位”为一个文件,它表明该脚本在结束之前就去世了。运行测试文件就会给你确切的错误消息。
最终的想法
即使测试应用程序是相当重要的,我知道你们中的一些人可能是想直接跳过这一天。我很高兴你没有。
当然,拥抱symfony框架提供ob娱乐下载学习所有伟大的功能,但它也对其发展和最佳实践哲学主张。和测试是其中之一。迟早,单元测试将为您保存一天。他们给你一个坚实的信心对你的代码和重构它没有恐惧的自由。单元测试是一个安全的守卫会告诉你,如果你打破的东西。symfob娱乐下载ony框架本身有9000多个测试。
明天,我们将编写一些功能测试工作
和类别
模块。在那之前,花点时间写更多Jobeet模型类的单元测试。
这项工作在Creative Commons许可Attribution-Share都3.0 Unported许可执照。