自动化测试是最大的进步之一从面向对象编程。特别是有利于开发web应用程序,他们可以保证应用程序的质量,即使释放很多。ob娱乐下载Symfony提供了各种工具,便于自动化测试,这些都是在这一章中引入的。
任何有经验的开发人员开发web应用程序非常清楚的时间做测试。编写测试用例,运行,分析结果是一个单调乏味的工作。此外,web应用程序的需求往往不断地变化,导致一个持续的释放和持续的代码重构的必要性。在这种情况下,可能会经常出现新的错误。
这就是为什么自动化测试是一个建议,如果不是必需的,一个成功的开发环境的一部分。一组测试用例可以保证应用程序实际上它应该做什么。即使内部往往改写,防止意外回归自动化测试。此外,他们强迫开发人员编写测试标准化,严格的格式能够理解一个测试框架。
自动化测试有时可以代替开发人员文档,因为他们可以清楚地说明一个应用程序应该做什么。欧宝官网下载app一个好的测试套件显示了输出应该预期的一组测试输入的,这是一个好方法来解释方法的目的。
symfob娱乐下载ony框架这一原则适用于本身。框架的内部是由自动化测试验证。这些单元测试和功能测试不捆绑标准symfony分布,但你可以检查他们从SVN储存库或在网上浏览ob娱乐下载http://trac.ob娱乐下载symfony-project.org/browser/branches/1.0/test。
单元测试确认统一的代码组件提供正确的输出对于一个给定的输入。他们验证函数和方法如何在每一个特定的情况下工作。单元测试一次处理一个案例中,例如一个方法可能需要几个单元测试,如果在某些情况下产生不一样的效果。
功能测试验证不是一个简单的input-to-output转换,但一个完整的功能。例如,缓存系统只能由一个功能测试验证,因为它涉及多个步骤:第一次请求页面时,它呈现;第二次,从缓存中。所以功能测试验证流程和需要的场景。在syob娱乐下载mfony中,你应该写为你所有的行为功能测试。
最复杂的相互作用,这两种类型可能不足。Ajax交互,例如,需要一个web浏览器执行JavaScript,因此自动测试需要一个特殊的第三方工具。此外,视觉效果只能由人类进行验证。
如果你有一个广泛的自动化测试方法,您将可能需要使用这些方法的组合。作为一个指导原则,记得保持简单测试和可读性。
请注意
自动化测试工作通过比较预期的输出结果。换句话说,他们评估断言(表达式= = 2美元)。断言的值真正的或假,它决定是否测试通过或失败。“断言”一词常用在处理自动化测试技术。
= = 2美元
真正的
假
在测试驱动开发(TDD)方法,测试在代码之前编写。先编写测试可以帮助你专注于一个函数应该完成的任务在实际发展之前。这是一个很好的实践,其他方法,如极限编程(XP),推荐。此外,它考虑了不可否认的事实,如果你不先编写单元测试,你永远不会写。
例如,假设你必须开发一个文本剥离功能。该函数删除空格字符串的开始和结束时,替换nonalphabetical字符,下划线,将所有大写字符转换为小写的。在测试驱动开发中,你将首先考虑所有可能的情况下,提供一个输入和预期输出为每个例子,如表15 - 1所示。
表15 - 1——一个测试用例列表文本剥离功能
“foo”
“foo栏”
“foo_bar”
“foo -): . . =酒吧?”
“__foo____bar_”
“FooBar”
“foobar
“别foo bar我!”
“don_t_foo_bar_me_”
你会写单元测试,运行他们,看到他们失败。然后您将添加必要的代码来处理第一个测试用例,再次运行测试,发现第一个通过,继续像这样。最终,通过所有的测试用例时,函数是正确的。
构建应用程序和一个测试驱动方法大致结束了测试代码和实际代码一样多。当你不想花时间调试你的测试用例,保持简单。
重构方法可以创建新的没有使用出现的错误。这就是为什么它也是一个很好的实践运行所有自动化测试在生产部署应用程序的新版本之前,这就是所谓的回归测试。
有许多单元测试框架在PHP的世界里,最出名是PhpUnit)和SimpleTest。ob娱乐下载Symfony的,叫做石灰。它是基于测试::Perl库,并利用兼容,这意味着测试结果显示为测试中指定的任何协议,为更好的可读性测试输出而设计的。
测试::
石灰提供了对单元测试的支持。它比其他的更轻量级的PHP测试框架和有几个优点:
lime.php
接下来使用石灰语法描述的各种测试。他们的工作与任何安装symfony。ob娱乐下载
单元测试和功能测试不应该启动生产。他们是开发工具,因此,他们应该运行在开发人员的电脑,主机服务器。
ob娱乐下载Symfony的单元测试是简单的PHP文件结束Test.php和位于测试/单位/应用程序的目录。他们遵循一个简单的和可读的语法。
Test.php
测试/单位/
清单15显示了一个典型的单元测试函数()函数。它开始由一个实例化的lime_test对象(你不需要担心现在的参数)。每个单元测试是调用一个方法lime_test实例。这些方法的最后一个参数永远是一个可选的字符串作为输出。
函数()
lime_test
清单15 - 1 -单元测试文件示例测试/单位/ strtolowerTest.php
测试/单位/ strtolowerTest.php
< ? php包括(目录名(__FILE__)。“/ . . /引导/ unit.php”);require_once(目录名(__FILE__)。“/ . . / . . / lib / strtolower.php”);$ t=新lime_test(7,新lime_output_color());/ /函数()$ t- >诊断接头(函数的作用是:“);$ t- >isa_ok(函数(“Foo”),“字符串”,函数的作用是:返回一个字符串的);$ t- >是(函数(“FOO”),“foo”,函数的作用是:将输入转换为小写的);$ t- >是(函数(“foo”),“foo”,函数的作用是:叶子小写字母不变的);$ t- >是(函数(“12 # ? @ ~”),“12 # ? @ ~”,函数的作用是:叶子非字母字符不变的);$ t- >是(函数(“FOO酒吧”),“foo酒吧”,函数的作用是:单独留下空白的);$ t- >是(函数(“FoO酒吧”),“foo酒吧”,函数的作用是处理输入的大小写混合);$ t- >是(函数(”),“foo”,函数的作用是:将空字符串转换为foo”);
从命令行启动测试设置的试验装置的任务。命令行输出是非常明确的,它可以帮助您定位哪个测试并没有通过。看到的输出示例测试清单一连。
试验装置
清单一连-从命令行启动一个单独的单元测试
> ob娱乐下载symfony函数试验装置1 . .7#函数()好吧1- - - - - -函数()返回一个字符串可以2- - - - - -函数() transforms the input to lowercase ok 3 - strtolower() leaves lowercase characters unchanged ok 4 - strtolower() leaves non alphabetical characters unchanged ok 5 - strtolower() leaves blanks alone ok 6 - strtolower() deals with mixed case input not ok 7 - strtolower() transforms empty strings into foo # Failed test (.\batch\test.php at line 21) # got: '' # expected: 'foo' # Looks like you failed 1 tests of 7.
提示
的包括语句的开头清单15 - 1是可选的,但它使测试文件一个独立的PHP脚本,您可以执行没有symfony命令行,通过调用ob娱乐下载php /单位/ strtolowerTest.php测试。
包括
php /单位/ strtolowerTest.php测试
的lime_test对象提供了大量的测试方法,如表一连中列出。
表一连——的方法lime_test对象的单元测试
诊断接头(msg)美元
ok(测试、味精美元)
(value1, value2美元,美元味精)
= =
不是(value1美元,美元value2,味精美元)
(字符串,regexp美元,美元味精)
不像(字符串,regexp美元、美元味精)
cmp_ok (value1,运营商,美元$ value2,味精美元)
isa_ok(变量,类型,美元味精美元)
isa_ok(对象,类,美元味精美元)
can_ok(对象、方法,美元味精美元)
is_deeply (array1, array2美元、美元味精)
include_ok(文件,味精美元)
失败()
通过()
跳过(味精、nb_tests美元)
nb_tests美元
待办事项()
语法很简单;注意,大多数方法作为他们最后的参数信息。这个信息显示在输出时,测试通过。实际上,学习这些方法的最好方法就是测试它们,所以看看清单3中,它使用。
清单3的测试方法lime_test对象,在测试/单位/ exampleTest.php
测试/单位/ exampleTest.php
< ? php包括(目录名(__FILE__)。“/ . . /引导/ unit.php”);/ /存根对象和函数用于测试目的类myObject{公共函数myMethod(){}}函数throw_an_exception(){扔新异常(“异常”);}/ /初始化测试对象$ t=新lime_test(16,新lime_output_color());$ t- >诊断接头(“hello world”);$ t- >好吧(1= =' 1 ',“相等操作符忽略类型”);$ t- >是(1,' 1 ',比较的字符串转换为数字的);$ t- >不是(0,1,0和1是不平等的);$ t- >就像(“test01”,' /测试\ d+ / ',“test01遵循测试编号模式”);$ t- >不像(“tests01”,' /测试\ d+ / ',“tests01并不遵循模式”);$ t- >cmp_ok(1,“<”,2,“一个不如两个”);$ t- >cmp_ok(1,“! = =”,真正的,一个和真实的不相同);$ t- >isa_ok(“foobar”,“字符串”,”\ 'foobar\ '是一个字符串的);$ t- >isa_ok(新myObject(),“myObject”,“新创建对象的类”);$ t- >can_ok(新myObject(),“myMethod”,的类myObject对象有一个myMethod方法”);array1美元=数组(1,2,数组(1= >“foo”,“一个”= >“4”));$ t- >is_deeply(array1美元,数组(1,2,数组(1= >“foo”,“一个”= >“4”)),第一个和第二个数组是相同的);$ t- >include_ok(”。/ fooBar.php ',“fooBar。php文件是正确地包括);试一试{throw_an_exception();$ t- >失败(“不应该抛出异常后执行代码”);}抓(异常$ e){$ t- >通过(“异常捕获成功”);}如果(!收取(foobar美元)){$ t- >跳过(跳过一个测试将测试计数精确条件的,1);}其他的{$ t- >好吧(foobar美元,“foobar”);}$ t- >待办事项(一个测试剩下要做的);
你会发现很多其他的例子,这些方法的使用symfony的单元测试。ob娱乐下载
你可能想知道为什么你会使用是()而不是好()在这里。错误消息输出是()更明确的;它显示了测试的成员,好()只是说,失败的状况。
是()
好()
的初始化lime_test对象需要作为它的第一个参数的数量应该执行的测试。如果测试最后执行的数量不同于这个数,石灰输出警告你。例如,清单3的测试集的输出如清单15。初始化规定,16个测试运行,但实际上只有15,所以输出指示。
清单15 -测试运行帮助你计划的统计测试
> ob娱乐下载symfony试验装置的例子1 . .16# hello world ok 1 - the equal operator ignores type ok 2 - a string is converted to a number for comparison ok 3 - zero and one are not equal ok 4 - test01 follows the test numbering pattern ok 5 - tests01 does not follow the pattern ok 6 - one is inferior to two ok 7 - one and true are not identical ok 8 - 'foobar' is a string ok 9 - new creates object of the right class ok 10 - objects of class myObject do have a myMethod method ok 11 - the first and the second array are the same not ok 12 - the fooBar.php file was properly included # Failed test (.\test\unit\testTest.php at line 27) # Tried to include './fooBar.php' ok 13 - exception catched successfully ok 14 # SKIP skipping one test to keep the test count exact in the condition ok 15 # TODO one test left to do # Looks like you planned 16 tests but only ran 15. # Looks like you failed 1 tests of 16.
的诊断接头()不算作为测试方法。用它来显示评论,这样您的测试输出保持组织和清晰。另一方面,待办事项()和跳过()算实际测试方法。一个通过()/失败()结合在一个试一试/抓块计数作为一个单独的测试。
诊断接头()
跳过()
试一试
抓
一个精心策划的测试策略必须包含预期数量的测试。你会发现它非常有用的验证自己的测试文件,特别是在复杂情况下运行测试内部条件或异常。如果测试失败在某种程度上,你会看到它很快因为运行测试的最终数量不匹配给定的初始化期间。
构造函数的第二个参数是一个输出对象扩展lime_output类。大部分时间,测试通过CLI是如何运行的,输出是一个lime_output_color对象,利用bash着色时可用。
lime_output
的试验装置从命令行任务,发射单元测试,预计测试名称的列表或一个文件模式。请参见清单15的细节。
清单今天-发射单元测试
/ /测试/单位/ myFunctionTest目录结构测试。php mySecondFunctionTest。php foo /巴特。php > ob娱乐下载symfony myFunction试验装置# # myFunctionTest运行。php > ob娱乐下载symfony试验装置myFunction mySecondFunction # #运行测试> symfony试验装置的foo / * # #运行巴特。php > ob娱乐下载symfony试验装置‘*’# #运行所有测试(递归)
在一个单元测试,半自动的功能默认是不活跃的。每个类中使用一个测试必须在测试文件中定义或要求作为外部依赖。这就是为什么许多测试文件开始和一群包括行,如清单15所示。
清单15中——包括类的单元测试
< ? php包括(目录名(__FILE__)。“/ . . /引导/ unit.php”);包括(目录名(__FILE__)。“/ . . / . . / config / config . php”);require_once(sf_sob娱乐下载ymfony_lib_dir美元。“/ util / sfToolkit.class.php”);$ t=新lime_test(7,新lime_output_color());/ / isPathAbsolute ()$ t- >诊断接头(“isPathAbsolute ()”);$ t- >是(sfToolkit::isPathAbsolute(/测试的),真正的,“isPathAbsolute()返回true,如果路径是绝对的);$ t- >是(sfToolkit::isPathAbsolute(”\ \测试”),真正的,“isPathAbsolute()返回true,如果路径是绝对的);$ t- >是(sfToolkit::isPathAbsolute(“C:\ \测试”),真正的,“isPathAbsolute()返回true,如果路径是绝对的);$ t- >是(sfToolkit::isPathAbsolute(“d: /测试”),真正的,“isPathAbsolute()返回true,如果路径是绝对的);$ t- >是(sfToolkit::isPathAbsolute(“测试”),假,“isPathAbsolute()返回false如果路径是相对的);$ t- >是(sfToolkit::isPathAbsolute(“. . /测试”),假,“isPathAbsolute()返回false如果路径是相对的);$ t- >是(sfToolkit::isPathAbsolute(“. .\ \测试”),假,“isPathAbsolute()返回false如果路径是相对的);
在单元测试中,你不仅需要实例化对象测试,而且它所依赖的对象。因为单元测试必须保持统一的,这取决于其他类可以不止一个的测试失败,如果一个类被打破了。此外,建立真正的对象可以是昂贵的,两行代码和执行时间。记住,速度是至关重要的单元测试,因为开发人员很快厌倦一个缓慢的过程。
当你开始为一个单元测试包括许多脚本,您可能需要一个简单的半自动的系统。为此,sfCore类(包括必须手动)提供了一个initSimpleAutoload ()方法,它需要一个绝对路径作为参数。坐落在这条路的所有类将自动装载。例如,如果你想要的所有类下sf_sob娱乐下载ymfony_lib_dir / util /美元自动装载,开始你的单元测试脚本如下:
sfCore
initSimpleAutoload ()
sf_sob娱乐下载ymfony_lib_dir / util /美元
require_once(sf_sob娱乐下载ymfony_lib_dir美元。“/ util / sfCore.class.php”);sfCore::initSimpleAutoload(sf_sob娱乐下载ymfony_lib_dir美元。' / util ');
生成的驱动对象依赖类的级联,所以只要你想测试驱动对象,半自动的是必要的。请注意,对于推动工作,您还需要包括下的文件供应商/推动目录(调用sfCore就变成了(SF_ROOT_DIR sfCore:: initSimpleAutoload(数组。”/lib/model', $sf_symfony_lib_dir.'/vendor/propel'));),然后将这些推动核心包括路径(通过调用set_include_path ($ sob娱乐下载f_symfony_lib_dir。/供应商的.PATH_SEPARATOR.SF_ROOT_DIR.PATH_SEPARATOR.get_include_path ()。
供应商/推动
(SF_ROOT_DIR sfCore:: initSimpleAutoload(数组。”/lib/model', $sf_symfony_lib_dir.'/vendor/propel'));
set_include_path ($ sob娱乐下载f_symfony_lib_dir。/供应商的.PATH_SEPARATOR.SF_ROOT_DIR.PATH_SEPARATOR.get_include_path ()
另一个不错的解决方案是使用存根半自动的问题。一个存根是另一个类的实现,真正的方法是简单的罐头数据所取代。它模仿真正的类的行为,但是没有成本。存根的一个很好的例子是一个数据库连接或web服务接口。在清单15-7中,映射的单元测试API依赖网络服务类。而不是叫真实fetch ()实际的web服务类的方法,测试使用存根返回测试数据。
网络服务
fetch ()
在单元测试中清单15-7——使用存根
require_once(目录名(__FILE__)。“/ . . / . . / lib / WebService.class.php”);require_once(目录名(__FILE__)。“/ . . / . . / lib / MapAPI.class.php”);类testWebService扩展网络服务{公共静态函数获取(){返回函数(目录名(__FILE__)。“/夹具/数据/ fake_web_service.xml”);}}美元关联=新MapAPI();$ t=新lime_test(1,新lime_output_color());$ t- >是(美元关联- >getMapSize(testWebService::获取(),One hundred.));
测试数据可以更复杂的字符串或调用一个方法。复杂的测试数据通常被称为夹具。编码清晰,最好经常保持设备在单独的文件,特别是如果他们是由多个单元测试文件使用。别忘了symfony,也可以轻易的YAML文件转ob娱乐下载换成一个数组sfYAML:负载()方法。这意味着,而不是写PHP数组,您可以编写您的测试数据在YAML文件,如清单8所示。
sfYAML:负载()
清单8 -在单元测试中使用夹具文件
/ /在fixtures.yml:-输入:/测试的输出:真正的备注:isPathAbsolute()返回真正的如果绝对路径,输入:”\ \测试”输出:真正的备注:isPathAbsolute()返回真正的如果绝对路径,输入:“C:\ \测试”输出:真正的备注:isPathAbsolute()返回真正的如果绝对路径,输入:“d: /测试”输出:真正的备注:isPathAbsolute()返回真正的如果绝对路径,输入:“测试”输出:假备注:isPathAbsolute()返回假如果路径是相对的,输入:“. . /测试”输出:假备注:isPathAbsolute()返回假如果路径是相对的,输入:“. .\ \测试”输出:假备注:isPathAbsolute()返回假如果路径是相对的/ /在testTest.php< ? php包括(目录名(__FILE__)。“/ . . /引导/ unit.php”);包括(目录名(__FILE__)。“/ . . / . . / config / config . php”);require_once(sf_sob娱乐下载ymfony_lib_dir美元。“/ util / sfToolkit.class.php”);require_once(sf_sob娱乐下载ymfony_lib_dir美元。“/ util / sfYaml.class.php”);测试点美元= sfYaml::负载(目录名(__FILE__)。' / fixtures.yml ');$ t=新lime_test(数(测试点美元),新lime_output_color());/ / isPathAbsolute ()$ t- >诊断接头(“isPathAbsolute ()”);foreach(测试点美元作为美元的情况下){$ t- >是(sfToolkit::isPathAbsolute(美元的情况下(“输入”]),美元的情况下(“输出”],美元的情况下(“评论”]);}
您的应用程序的功能测试验证部分。他们模拟浏览会话,发出请求,并检查元素反应,就像你会做手工验证一个动作做它应该做什么。在功能测试中,您运行一个对应于一个用例场景。
你可以运行功能测试使用文本浏览器和很多正则表达式的断言,但这将是一个伟大的浪费时间。ob娱乐下载Symfony提供了一个特殊的对象,调用sfBrowser,它就像一个浏览器连接到一个symfony应用程序不需要服务器,没有减速的HTTP传输ob娱乐下载。它给访问的核心对象每个请求(请求、会话、上下文和响应对象)。ob娱乐下载Symfony还提供了一个扩展这个类的调用sfTestBrowser,专门为功能测试的能力sfBrowser对象+一些聪明的assert方法。
sfBrowser
sfTestBrowser
功能测试通常始于一个测试浏览器对象的初始化。这个对象发出请求的行动和验证一些元素存在于反应。
例如,每次你生成一个模块框架init-module或者是propel-init-crud任务,symfob娱乐下载ony创建了一个简单的功能测试模块。测试发出请求的默认操作模块和检查响应状态码,路由系统计算模块和行动,并存在一定的句子响应内容。对于一个foobar模块,生成的foobarActionsTest.php文件清单15-9看起来像。
init-module
propel-init-crud
foobar
foobarActionsTest.php
清单15-9——一个新模块的默认功能测试测试/功能/前端/ foobarActionsTest.php
测试/功能/前端/ foobarActionsTest.php
< ? php包括(目录名(__FILE__)。“/ . . / . . /引导/ functional.php”);/ /创建一个新的测试浏览器美元的浏览器=新sfTestBrowser();美元的浏览器- >初始化();美元的浏览器- >得到(“foobar /指数”)- >isStatusCode(200年)- >isRequestParameter(“模块”,“foobar”)- >isRequestParameter(“行动”,“指数”)- >checkResponseElement(“身体”,”!/This is a temporary page/');
浏览器返回一个方法sfTestBrowser对象,因此您可以链方法调用你的测试文件的可读性。这被称为流体接口对象,因为没有停止流动的方法调用。
一个功能测试可以包含多个请求和更复杂的断言;你很快就会发现所有的可能性在接下来的部分。
推出一个功能测试,使用test-functionalsymfony命令行任务,如ob娱乐下载清单10所示。这个任务预计应用程序名称和一个测试名称(省略了Test.php后缀)。
test-functional
清单10 -从命令行启动一个功能测试
> ob娱乐下载symfony test-functional前端foobarActions # /评论/索引好的1 -状态代码是200好2 -请求参数模块foobar好3 -请求参数行动指数不可以4 -响应选择身体不匹配正则表达式/这是一个临时的页面/ #看起来像你失败了1 4的测试。1 . . 4
为一个新模块生成的功能测试不通过默认情况下。这是因为在一个新创建的模块,指数行动将祝贺页面(包括在symfonyob娱乐下载默认的模块),其中包含的句子“这是一个临时页面”。只要你不修改指数行动,这个模块将会失败的测试,这保证你不能与一个未完成的模块通过所有测试。
指数
默认的
在功能测试中,半自动的激活,所以你不需要包含的文件。
测试浏览器能够发出GET和POST请求。在这两种情况下,使用一个真正的URI作为参数。清单15-11展示了如何编写调用sfTestBrowser对象来模拟请求。
与清单15-11 -模拟请求sfTestBrowser对象
包括(目录名(__FILE__)。“/ . . / . . /引导/ functional.php”);/ /创建一个新的测试浏览器b美元=新sfTestBrowser();b美元- >初始化();b美元- >得到(“foobar /显示/ id / 1”);/ /获取请求b美元- >帖子(“foobar /显示”,数组(“id”= >1));/ / POST请求/ / get()和post()方法调用快捷方式()方法b美元- >调用(“foobar /显示/ id / 1”,“得到”);b美元- >调用(“foobar /显示”,“职位”,数组(“id”= >1));/ /调用()方法可以用任何方法模拟请求b美元- >调用(“foobar /显示/ id / 1”,“头”);b美元- >调用(“foobar /添加/ id / 1”,“把”);b美元- >调用(“foobar /删除/ id / 1”,“删除”);
一个典型的浏览会话包含不仅要求具体行动,而且点击链接,浏览器按钮。见清单15-12,sfTestBrowser对象也能模拟。
清单15-12 -模拟导航的sfTestBrowser对象
b美元- >得到(' / ');/ /请求到主页b美元- >得到(“foobar /显示/ id / 1”);b美元- >回来();/ /回历史的一页b美元- >向前();/ /一页历史b美元- >重新加载();/ /重新加载当前页面b美元- >点击(“去”);/ /寻找“go”链接或按钮,单击它
测试浏览器处理一堆电话,所以回()和转发()方法工作时做一个真正的浏览器。
回()
转发()
测试浏览器都有自己的机制来管理会话(sfTestStorage)和饼干。
sfTestStorage
之间的相互作用,大多数需要测试,可能那些与表单相关的排名第一。模拟形式输入和提交,你有三个选择。你可以做一个你想发送POST请求的参数,调用click ()形式参数作为数组,或填写字段,单击submit按钮。不管怎样他们都导致相同的POST请求。战绩清单显示了一个示例。
click ()
战绩清单——模拟表单输入sfTestBrowser对象
/ /例子模板模块/ foobar /模板/ editSuccess.php< ? php回声form_tag(“foobar /更新”)? >< ? php回声input_hidden_tag(“id”,sf_params美元- >得到(“id”))? >< ? php回声input_tag(“名字”,“foo”)? >< ? php回声submit_tag(“去”)? >< ? php回声文本区域(“text1”,“foo”)? >< ? php回声文本区域(“text2”,“酒吧”)? >> < /形式/ /功能测试例子的这种形式b美元=新sfTestBrowser();b美元- >初始化();b美元- >得到(“foobar /编辑/ id / 1”);/ /选项1:POST请求b美元- >帖子(“foobar /更新”,数组(“id”= >1,“名字”= >“假”,“提交”= >“去”));/ /选项2:单击submit按钮与参数b美元- >点击(“去”,数组(“名字”= >“假”));/ /选项3:输入表单值字段,字段名称然后单击submit按钮b美元- >setField(“名字”,“假”)- >点击(“去”);
第二个和第三个选项,默认表单值被自动包含在表单提交,和表单不需要指定目标。
当一个动作完成的重定向(),测试浏览器不能自动遵循重定向;您必须手动跟随它followRedirect (),如清单15所示。
重定向()
followRedirect ()
清单15 - - - - - - -测试浏览器不能自动重定向
/ /例子/ foobar /动作/ actions.class.php行动模块公共函数executeUpdate(){…这个美元- >重定向(“foobar /显示? id =”。这个美元- >getRequestParameter(“id”));}/ /这个动作的示例功能测试b美元=新sfTestBrowser();b美元- >初始化();b美元- >得到(“foobar /编辑? id = 1”)- >点击(“去”,数组(“名字”= >“假”))- >isRedirected()- >/ /检查请求重定向followRedirect();/ /手动重定向
有最后一个方法你应该知道这是有用的浏览:重启()重新启动浏览历史、会话和饼干,如果你重新启动浏览器。
重启()
一旦做出了第一个请求,sfTestBrowser对象可以访问请求时,上下文,和响应对象。这意味着你可以检查很多东西,从文本内容响应头,请求参数,和配置:
美元的请求=b美元- >getRequest();美元的上下文=b美元- >getContext();美元的反应=b美元- >getResponse();
侧边栏
sfBrowser对象
清单10中的所有浏览方法描述战绩也可用的测试范围,整个sfBrowser对象。你可以称之为如下:
/ /创建一个新的浏览器b美元=新sfBrowser();b美元- >初始化();b美元- >得到(“foobar /显示/ id / 1”)- >setField(“名字”,“假”)- >点击(“去”);美元的内容=b美元- >getResponse()- >getContent();…
的sfBrowser批处理脚本对象是一个非常有用的工具,例如,如果您想要浏览的列表页面生成缓存版本为每个(请参考第18章详细的例子)。
由于sfTestBrowser对象能够访问请求的响应和其他组件,这些组件可以做测试。你可以创建一个新的lime_test对象为目的,但幸运的是sfTestBrowser提出了一种测试()方法返回一个lime_test对象,您可以调用单元断言前面描述的方法。检查清单领路人依旧看到如何通过做断言sfTestBrowser。
测试()
清单领路人依旧—测试浏览器提供了测试的能力测试()方法
b美元=新sfTestBrowser();b美元- >初始化();b美元- >得到(“foobar /编辑/ id / 1”);美元的请求=b美元- >getRequest();美元的上下文=b美元- >getContext();美元的反应=b美元- >getResponse();/ /获得lime_test方法通过测试()方法b美元- >测试()- >是(美元的请求- >getParameter(“id”),1);b美元- >测试()- >是(美元的反应- >getStatuscode(),200年);b美元- >测试()- >是(美元的反应- >getHttpHeader(“内容类型”),“text / html; charset = utf - 8”);b美元- >测试()- >就像(美元的反应- >getContent(),“编辑/”);
的getResponse (),getContext (),getRequest (),测试()方法不返回一个sfTestBrowser对象,因此你不能链sfTestBrowser方法调用。
getResponse ()
getContext ()
getRequest ()
您可以检查传入和传出的饼干很容易通过请求和响应对象,如清单16所示。
清单15 - 16 -测试饼干sfTestBrowser
b美元- >测试()- >是(美元的请求- >getCookie(“foo”),“酒吧”);/ /传入的饼干美元的饼干=美元的反应- >getCookies();b美元- >测试()- >是(美元的饼干(“foo”],“foo = bar”);/ /输出饼干
使用测试()方法测试请求元素结束的长队。幸运的是,sfTestbrowser包含很多代理方法,帮助你保持你的功能测试可读和短——除了返回一个sfTestBrowser对象本身。例如,您可以重写清单领路人依旧以更快的方式,如清单15 - 17所示。
sfTestbrowser
直接与清单15 - 17 -测试sfTestBrowser
b美元=新sfTestBrowser();b美元- >初始化();b美元- >得到(“foobar /编辑/ id / 1”)- >isRequestParameter(“id”,1)- >isStatusCode()- >isResponseHeader(“内容类型”,text / html;charset = utf - 8 ')- >responseContains(“编辑”);
状态200年预计参数的默认值isStatusCode (),所以你可以叫它没有任何参数测试成功的响应。
isStatusCode ()
代理方法的一个优点是,你不需要指定一个输出文本是你拥有lime_test方法。消息代理自动生成的方法,测试输出是清晰可读。
# / foobar /编辑/身份证/ 1好1 -请求参数“id”是“1”好2 -状态代码是“200”好3 -响应头“内容类型”是“text / html”好4 -响应包含“编辑”1 . . 4
在实践中,代理的清单15 - 17日覆盖大多数常见的测试方法,所以你将很少使用测试()方法在一个sfTestBrowser对象。
清单15显示sfTestBrowser不能自动重定向。这有一个优势:你可以测试一个重定向。例如,清单15显示了如何测试清单15的反应。
清单15—-测试重定向sfTestBrowser
b美元=新sfTestBrowser();b美元- >初始化();b美元- >得到(“foobar /编辑/ id / 1”)- >点击(“去”,数组(“名字”= >“假”))- >isStatusCode(200年)- >isRequestParameter(“模块”,“foobar”)- >isRequestParameter(“行动”,“更新”)- >isRedirected()- >/ /检查反应是一个重定向followRedirect()- >/ /手动重定向isStatusCode(200年)- >isRequestParameter(“模块”,“foobar”)- >isRequestParameter(“行动”,“显示”);
许多功能测试验证页面检查文本的存在是正确的内容。在正则表达式的帮助responseContains ()方法,您可以检查显示文本,一个标签的属性或值。但只要你想检查什么响应中深埋地下的DOM,正则表达式是不理想。
responseContains ()
这就是为什么sfTestBrowser对象支持getResponseDom ()方法。它返回一个libXML2 DOM对象,更容易比纯文本分析和测试。请参考清单15 - 19使用这种方法的一个例子。
getResponseDom ()
清单15 - 19 -测试浏览器访问响应内容作为DOM对象
b美元=新sfTestBrowser();b美元- >初始化();b美元- >得到(“foobar /编辑/ id / 1”);dom美元=b美元- >getResponseDom();b美元- >测试()- >是(dom美元- >getElementsByTagName(“输入”)- >项(1)- >getAttribute(“类型”),“文本”);
但与PHP的DOM方法解析HTML文档还不够快速和容易。如果您熟悉CSS选择器,你知道他们是一个更强大的方法来检索元素从一个HTML文档。ob娱乐下载Symfony提供了一个工具类sfDomCssSelector预计一个DOM文档作为施工参数。它有一个gettext()方法,它返回一个字符串数组根据CSS选择器,和一个getElements()方法,它返回一个DOM元素数组。清单15 - 20中看到的一个例子。
sfDomCssSelector
清单15 - 20 -测试浏览器给响应内容的访问sfDomCssSelector对象
b美元=新sfTestBrowser();b美元- >初始化();b美元- >得到(“foobar /编辑/ id / 1”);$ c=新sfDomCssSelector(b美元- >getResponseDom())b美元- >测试()- >是($ c- >gettext(表单输入(type = "隐藏"]”(value = " 1 ")),数组(”);b美元- >测试()- >是($ c- >gettext(“形式textarea [name = " text1 "] '),数组(“foo”));b美元- >测试()- >是($ c- >gettext(的表单输入(type =“提交”)”),数组(”));
在其不断追求简洁和清晰,symfony提供了一个快捷方式:ob娱乐下载checkResponseElement ()代理方法。这种方法使清单15 -类似于清单15至21。
checkResponseElement ()
清单15至21 -测试浏览器访问元素的CSS选择器的响应
b美元=新sfTestBrowser();b美元- >初始化();b美元- >得到(“foobar /编辑/ id / 1”)- >checkResponseElement(表单输入(type = "隐藏"]”(value = " 1 "),真正的)- >checkResponseElement(“形式textarea [name = " text1 "] ',“foo”)- >checkResponseElement(的表单输入(type =“提交”)”,1);
的行为checkResponseElement ()方法的第二个参数的类型取决于它接收:
!
方法接受第三个可选参数,在一个关联数组的形状。它允许您执行的测试,而不是选择器返回的第一个元素(如果它返回几个),但是在另一个元素在一定的位置,如清单第15 - 22所示。
使用位置选项清单第15 - 22 -匹配一个元素在一定的位置
b美元=新sfTestBrowser();b美元- >初始化();b美元- >得到(“foobar /编辑? id = 1”)- >checkResponseElement(“表单文本区域”,“foo”)- >checkResponseElement(“表单文本区域”,“酒吧”,数组(“位置”= >1));
选项数组也可以用于执行两个测试在同一时间。您可以测试有一个元素匹配选择器和有多少,如清单15 - 23所示。
清单15 - 23 -使用计数选项数的数量匹配
b美元=新sfTestBrowser();b美元- >初始化();b美元- >得到(“foobar /编辑? id = 1”)- >checkResponseElement(表单输入的,真正的,数组(“数”= >3));
选择器是非常强大的工具。它接受大部分的CSS 2.1选择器,您可以使用它为复杂的查询,如清单15 - 24。
清单15 - 24 - CSS选择器接受复杂的例子checkResponseElement ()
b美元- >checkResponseElement(“李ul #列表(href)”,点击我的);b美元- >checkResponseElement(“李ul >”,点击我的);b美元- >checkResponseElement(“李ul +”,点击我的);b美元- >checkResponseElement(h1, h2的,点击我的);b美元- >checkResponseElement(“[类美元= " foo "] [href * = " bar.html "] ',“我的链接”);
的sfTestBrowser对象使用一个特殊的前端控制器,设置为测试环境。这种环境的默认配置如清单15 - 25所示。
测试
清单15 - 25 -默认测试环境配置myapp / config / settings.yml
myapp / config / settings.yml
测试:.settings: # E_ALL |代码& ~ E_NOTICE = 2047 error_reporting: 2047缓存:从web_debug:从no_script_name:从etag:
缓存和web调试工具栏设置从在这种环境下。然而,一个日志文件中的代码执行仍然留下痕迹,截然不同dev和刺激日志文件,这样你可以检查它独立(myproject /日志/ myapp_test.log)。在这种环境下,异常不要停止脚本的执行,所以,您可以运行整个组即使一个失败的测试。你可以有特定的数据库连接设置,例如,使用另一个数据库测试数据。
从
dev
刺激
myproject /日志/ myapp_test.log
在使用之前sfTestBrowser对象,你必须初始化它。如果你需要,你可以指定应用程序的主机名和IP地址为客户机——也就是说,如果你的应用程序控制这两个参数。清单15-26演示了如何做到这一点。
清单15-26 -设置测试浏览器与主机名和IP
b美元=新sfTestBrowser();b美元- >初始化(“myapp.example.com”,“123.456.789.123”);
的test-functional任务可以运行一个或多个功能测试,根据参数的数量。看起来很像的规则试验装置任务,除了功能测试任务总是期望应用程序作为第一个参数,如清单15 -所示。
清单15 - - - - - - -语法功能测试任务
/ /测试目录结构测试/功能/前端/ myModuleActionsTest。php myScenarioTest。php后端/ myOtherScenarioTest.php## Run all functional tests for one application, recursively > symfony test-functional frontend ## Run one given functional test > symfony test-functional frontend myScenario ## Run several tests based on a pattern > symfony test-functional frontend my*
本节列出了一些良好的实践来保持你的测试组织和易于维护。建议关注文件组织、单元测试和功能测试。
至于文件结构,您应该使用类的单元测试文件名称他们应该测试,功能测试文件和名称使用模块或他们应该测试的场景。请参见清单15-28为例。你的测试/目录将包含大量的文件,并找到一个测试可能困难从长远来看,如果你不遵循这些指导方针。
测试/
清单15-28 -示例文件命名惯例
测试/单位/ myFunctionTest。php mySecondFunctionTest。php foo /巴特。php功能/前端/ myModuleActionsTest。php myScenarioTest。php后端/ myOtherScenarioTest.php
对于单元测试,一个好的实践是组函数或方法的测试,并开始每个测试组诊断接头()调用。每个单元测试的信息应该包含测试函数或方法的名称,后跟一个动词和一个属性,以便测试输出看起来就像一个句子描述一个对象的属性。清单15 - 29显示了一个示例。
清单15 - 29 -单元测试命名实践示例
/ /函数()$ t- >诊断接头(函数的作用是:“);$ t- >isa_ok(函数(“Foo”),“字符串”,函数的作用是:返回一个字符串的);$ t- >是(函数(“FOO”),“foo”,函数的作用是:将输入转换为小写的);#函数()好吧1- - - - - -函数()返回一个字符串可以2- - - - - -函数()将输入转换为小写的
功能测试应按页面和分组从一个请求开始。清单15 - 30演示了这种做法。
清单15 - 30 -功能测试命名实践示例
美元的浏览器- >得到(“foobar /指数”)- >isStatusCode(200年)- >isRequestParameter(“模块”,“foobar”)- >isRequestParameter(“行动”,“指数”)- >checkResponseElement(“身体”,“foobar /”);# /评论/索引好吧1——状态代码200年好吧2——请求参数模块foobar ok3——请求参数指数可以采取行动4身体-响应选择器匹配正则表达式/ foobar /
如果你遵循这个惯例,您的测试的输出将足够干净的使用作为一个开发人员项目的文档,所以在某些情况下,使实际无用的文档。欧宝官网下载app
symfony提供的单元测试和功能测试工具在大多数情况下应该足够了。ob娱乐下载这里列出了一些额外的技术来解决在自动化测试常见问题:启动测试在一个孤立的环境中,访问数据库中测试,测试缓存和测试在客户端交互。
的试验装置和test-functional任务可以启动一个单独的测试或一组测试。但是如果你把这些任务没有任何参数,他们将所有的单元测试和功能测试用测试/目录中。参与一个特定的机制来隔离在一个独立的沙箱中,每个测试文件,以避免污染风险之间的测试。此外,它不会意义保持相同的输出与单一测试文件在这种情况下(输出数千行长),测试结果是压实成合成视图。这就是为什么大量的测试文件的执行使用测试工具,也就是说,一个自动化测试框架有特殊的能力。石灰的测试装具模块依赖于一个组件框架lime_harness。它显示了一个测试状态文件文件,概述的总数量的测试通过了,如你所见清单15-31。
lime_harness
清单15-31 -启动所有的测试测试工具
> ob娱乐下载symfony测试所有单位/ myFunctionTest.php ................好的单位/ mySecondFunctionTest.php ..........好的单位/ foo / barTest.php ...................不可以失败的测试统计总失败的失败- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -单位/ foo /巴特。php 0 2 2 62 63失败了1/3的测试脚本,66.66%好了。2/53单项成绩失败,96.22%好了。
测试执行一样当你叫他们一个接一个,只输出是由短是真正有用的。特别是,最后图着重于失败的测试,并帮助你找到他们。
您可以启动所有的测试一个调用使用测试所有任务,也使用测试工具,如清单15-32所示。这是你应该做的每转到生产之前,确保没有回归以来出现的最新版本。
测试所有
清单15-32 -发射的所有测试项目
> ob娱乐下载symfony测试所有
单元测试通常需要访问数据库。自动初始化数据库连接时调用sfTestBrowser: get ()第一次。然而,如果你想访问数据库之前使用sfTestBrowser,你必须初始化sfDabataseManager手动对象,如清单15-33所示。
sfTestBrowser: get ()
sfDabataseManager
在测试清单15-33 -初始化数据库
databaseManager美元=新sfDatabaseManager();databaseManager美元- >初始化();/ /可选地,您可以检索当前数据库连接反对美元=推动:getConnection();
你应该使用夹具在开始测试之前填充数据库。这可以通过完成sfPropelData对象。这个对象可以从文件加载数据,就像propel-load-data任务,或从一个数组,如清单15 - 34所示。
sfPropelData
propel-load-data
清单15 - 34 -填充一个数据库从一个测试文件
元数据=新sfPropelData();/ /从文件加载数据元数据- >loadData(sfConfig::得到(“sf_data_dir”)。“/夹具/ test_data.yml”);/ /加载数据数组美元的固定装置=数组(“文章”= >数组(“article_1”= >数组(“标题”= >“foo名称”,“身体”= >“酒吧的身体”,“created_at”= >时间(),),“article_2”= >数组(“标题”= >“foo foo名称”,“身体”= >“酒吧酒吧的身体”,“created_at”= >时间(),),),);元数据- >loadDataFromArray(美元的固定装置);
然后,使用驱动对象作为你会在一个正常的应用程序中,根据您的测试需求。记得在单元测试中包括他们的文件(您可以使用sfCore: initSimpleAutoload()方法来自动化,在小费的“存根、装置和加载”部分之前在这一章)。推动对象自动装载在功能测试。
当您为应用程序启用高速缓存时,功能测试验证缓存行为应该做像预期的那样工作。
首先要做的是测试环境(在启用缓存settings.yml文件)。然后,如果你想测试是否一个页面来自缓存还是生成,您应该使用isCached ()提供的测试方法sfTestBrowser对象。清单15 35展示了这种方法。
settings.yml
isCached ()
清单15 35 -测试的缓存isCached ()方法
< ? php包括(目录名(__FILE__)。“/ . . / . . /引导/ functional.php”);/ /创建一个新的测试浏览器b美元=新sfTestBrowser();b美元- >初始化();b美元- >得到(' / mymodule里');b美元- >isCached(真正的);/ /检查来自缓存的响应b美元- >isCached(真正的,真正的);/ /检查缓存的响应有布局b美元- >isCached(假);/ /检查不是来自缓存的响应
你不需要清除缓存功能测试的开始;引导脚本是否适合你。
前面描述的技术的主要缺点是,他们不能模拟JavaScript。使用Ajax交互等非常复杂的相互作用,例如,你需要能够准确地再现鼠标和键盘的输入,用户在客户端会做和执行脚本。通常,这些测试是手工复制的,但他们非常耗时且容易出错。
解决方案被称为硒(http://www.openqa.org/selenium/),这是一个完全用JavaScript编写的测试框架。它执行的一组操作在一个页面上就像一个普通用户,使用当前的浏览器窗口。的优势sfBrowser对象是硒能够执行JavaScript的页面,所以你甚至可以测试Ajax交互。
硒与symfony默认绑定。ob娱乐下载要安装它,您需要创建一个新的硒/目录在你的web /目录,并在解压缩的内容硒存档(http://www.openqa.org/selenium-core/download.action)。这是因为硒依赖于JavaScript,大多数浏览器的安全设置标准不允许它运行,除非它是可用的应用程序相同的主机和端口。
硒/
web /
谨慎
小心不要转移硒/目录到您的生产服务器,因为这将由谁获得访问您的web文档根通过浏览器。
Selenium测试都写在HTML和存储web /硒/测试/目录中。例如,清单15-36显示一个主页加载的功能测试,点击链接点击我,文本“Hello, World”是在响应中寻找。记住,为了访问的应用程序测试环境中,您必须指定myapp_test.php前端控制器。
web /硒/测试/
myapp_test.php
清单15-36 - Selenium测试样本web /硒/测试/ testIndex.html
web /硒/测试/ testIndex.html
< !DOCTYPE html公共”——/ / W3C / / DTD HTML 4.01过渡/ / EN”> < html > = <头> < meta内容“text / html;charset = utf - 8”http-equiv =“内容类型”> <标题>指数测试< /名称> < /头> <身体> <表格单元格间距=“0”tbody > > < < tr > < td colspan =“3”> < / td的第一步> < / tr > < tr > < td > < / td > < td > / myapp_test开放。php / < / td > < td >, < / td > < / tr > < tr > < td > clickAndWait < / td > = < td >链接点击我< / td > < td >, < / td > < / tr > < tr > < td > assertTextPresent < / td > < td >你好,世界!< / td > < td >, < / td > < / tr > < / tbody > < /表> < /身体> < / html >
一个测试用例是由一个HTML文档,其中包含一个表有三列:命令,目标,和价值。但是,并不是所有命令将一个值。在这种情况下,要么离开列空白或使用,使表看起来更好。指的是硒网站命令的完整列表。
,
您还需要添加这个测试全球测试套件的表中插入一个新行TestSuite.html文件位于相同的目录中。清单样本显示。
TestSuite.html
清单样本,测试套件中添加一个测试文件,web /硒/测试/ TestSuite.html
web /硒/测试/ TestSuite.html
…< tr > < td > < a href = " / testIndex。html >我的第一个测试< / > < / td > < / tr >…
要运行测试,只需浏览
http://myapp.example.com/selenium/index.html
选择主要的测试套件,单击按钮来运行所有测试,观察你的浏览器,因为它重现的步骤,你告诉它。
Selenium测试运行在一个真正的浏览器,他们还允许您测试浏览器不一致。与一个浏览器建立您的测试和测试他们的所有其他站点应该处理一个请求。
Selenium测试的事实都写在HTML可以写作Selenium测试的麻烦。但由于Firefox扩展(硒http://seleniumrecorder.mozdev.org/),只需要创建一个测试是执行测试一次会话记录。导航在录音时,您可以添加assert-type测试通过在浏览器窗口中单击鼠标右键并选择适当的检查下添加硒在弹出菜单命令。
你可以保存测试一个HTML文件为您的应用程序构建一个测试套件。Firefox扩展甚至允许你运行Selenium测试记录。
不要忘记重新启动启动Selenium测试前测试数据。
自动化测试包括单元测试来验证方法或函数和功能测试来验证功能。ob娱乐下载Symfony依赖于石灰测试单元测试和提供了一个框架sfTestBrowser类特别是对于功能测试。他们都提供了许多断言方法,从基本到最先进的,像CSS选择器。使用symfonob娱乐下载y命令行启动测试,(一个接一个试验装置和test-functional任务)或测试工具(测试所有的任务)。在处理数据时,自动化测试使用fixture和存根,这很容易实现在symfony的单元测试。ob娱乐下载
如果你一定要写单元测试足以覆盖大部分应用程序(可能使用TDD方法),你会觉得更安全的重构内部或添加新特性时,你甚至可能获得一些时间在文档的任务。欧宝官网下载app
这项工作是GFDL许可执照。