测试

编辑本页

警告:您正在浏览的文档欧宝体育电话<一个href="//www.oldmanjams.com/releases/5.0">欧宝娱乐app下载地址Symfony 5.0,现已不再维护。

读<一个href="//www.oldmanjams.com/doc/current/testing.html">本页的更新版本用于Sy欧宝娱乐app下载地址mfony 6.2(当前稳定版本)。

测试

每当您编写新的代码行时,您也可能会添加新的错误。为了构建更好、更可靠的应用程序,应该同时使用功能测试和单元测试来测试代码。

PHPUnit测试框架

欧宝娱乐app下载地址Symfony集成了一个名为<一个href="https://phpunit.de/" class="reference external" rel="external noopener noreferrer" target="_blank">PHPUnit)为您提供一个丰富的测试框架。本文不会涉及PHPUnit本身,它有自己的优点<一个href="https://phpunit.readthedocs.io/" class="reference external" rel="external noopener noreferrer" target="_blank">欧宝体育电话

在创建第一个测试之前,请安装<一个href="//www.oldmanjams.com/components/PHPUnit%20Bridge" class="reference external">桥接组件,它包装了原始的PHPUnit二进制文件,以提供额外的功能:

1
创建symfony/phpunit-bridg欧宝娱乐app下载地址e

在库下载后,尝试通过运行来执行PHPUnit(第一次运行时,它会下载PHPUnit本身,并使它的类在你的应用程序中可用):

1
/ bin / phpunit)

请注意

/ bin / phpunit)命令由<一个href="//www.oldmanjams.com/doc/5.0/setup.html" class="reference internal">欧宝娱乐app下载地址Symfony Flex安装phpunit-bridge包中。如果该命令缺失,您可以删除包(作曲家删除symfony/php欧宝娱乐app下载地址unit-bridge)并重新安装。另一个解决方案是删除项目的欧宝娱乐app下载地址symfony.lock文件并运行作曲家安装强制执行所有Symfony Flex配方。欧宝娱乐app下载地址

每个测试——无论是单元测试还是功能测试——都是一个PHP类,应该存在于测试/应用程序的目录。如果您遵循此规则,那么您可以使用与之前相同的命令运行应用程序的所有测试。

PHPUnit由phpunit.xml.dist在Symfony应用程序的根目录下。欧宝娱乐app下载地址

提示

方法可以生成代码覆盖——覆盖- *选项,请参阅使用时显示的帮助信息——帮助获取更多信息。

单元测试

单元测试是针对单个PHP类的测试,也称为单位.如果您想测试应用程序的整体行为,请参阅有关的部分<一个href="//www.oldmanjams.com/doc/5.0/testing.html" class="reference internal">功能测试

编写Symfon欧宝娱乐app下载地址y单元测试与编写标准的PHPUnit单元测试没有什么不同。假设,比如说,你有一个令人难以置信的类调用计算器src / Util /应用目录:

1 2 3 4 5 6 7 8 9 10
/ / src / Util / Calculator.php名称空间应用程序跑龙套计算器公共函数添加一个b返回一个+b;}}

要测试这一点,可以创建一个CalculatorTest测试/ Util申请目录:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/ /测试/ Util / CalculatorTest.php名称空间应用程序测试跑龙套使用应用程序跑龙套计算器使用PHPUnit)框架TestCaseCalculatorTest扩展TestCase公共函数testAdd()计算器计算器();结果计算器->add (30.12);//你的计算器加的数是正确的!->assertequal (42结果);}}

请注意

按照惯例,测试/目录应为单元测试复制应用程序的目录。的类中测试类src / Util /目录,将测试放在测试/ Util /目录中。

就像在您的实际应用程序-自动加载是自动启用通过供应商/ autoload.php文件中默认配置的phpunit.xml.dist文件)。

您还可以将测试运行限制到一个目录或特定的测试文件:

1 2 3 4 5 6 7 8
#运行应用程序的所有测试php bin / phpunit)#运行Util/目录下的所有测试php bin/phpunit tests/Util . php#运行计算器类的测试php bin/phpunit tests/Util/CalculatorTest.php

功能测试

功能测试检查应用程序不同层(从路由到视图)的集成。就PHPUnit而言,它们与单元测试没有什么不同,但它们有一个非常具体的工作流程:

  • 提出请求;
  • 点击链接或提交表单;
  • 测试响应;
  • 清洗并重复。

在创建第一个测试之前,请安装以下包,这些包提供了功能测试中使用的一些实用程序:

1
Composer require——dev s欧宝娱乐app下载地址ymfony/browser-kit symfony/css-selector

你的第一个功能测试

功能测试是PHP文件,通常位于测试/控制器应用程序的目录。如果您想测试由您的为PostController类,首先创建一个newPostControllerTest.php扩展特殊类型的文件WebTestCase类。

举个例子,一个测试可以是这样的:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/ /测试/控制器/ PostControllerTest.php名称空间应用程序测试控制器使用欧宝娱乐app下载地址FrameworkBundle测试WebTestCasePostControllerTest扩展WebTestCase公共函数testShowPost()客户端静态::createClient ();客户端->请求(“得到”' / post / hello world ');->assertequal (200客户端->getResponse ()->getStatusCode ());}}

提示

要运行功能测试,请使用WebTestCase类需要知道哪个是应用程序内核来引导它。内核类通常定义在KERNEL_CLASS环境变量(包含在默认值中.env.test文件由Symfony提供):欧宝娱乐app下载地址

如果您的用例更复杂,您还可以重写createKernel ()getKernelClass ()方法,这些方法优先于KERNEL_CLASSenv var。

在上面的示例中,您验证了HTTP响应是否成功。下一步是验证页面是否实际包含预期的内容。的createClient ()方法返回一个客户端,它就像一个浏览器,你将使用它来抓取你的网站:

1
履带客户端->请求(“得到”' / post / hello world ');

请求()方法(读<一个href="//www.oldmanjams.com/doc/5.0/testing.html" class="reference internal">关于请求方法的更多信息)返回一个<一个href="https://github.com/symfony/symfony/blob/5.0/src/Symfony/Component/DomCrawler/Crawler.php" class="reference external" title="履带" rel="external noopener noreferrer" target="_blank">履带对象,可用于在响应中选择元素、单击链接和提交表单。

提示

履带只有当响应是XML或HTML文档时才有效。要获得原始内容响应,请调用客户端- > getResponse()——> getContent ()

爬虫集成了欧宝娱乐app下载地址symfony / css选择器组件提供CSS选择器查找页面内容的功能。要安装CSS选择器组件,运行:

1
——开发symfony/css-selecto欧宝娱乐app下载地址r

现在你可以在爬虫中使用CSS选择器了。要断言短语“Hello World”出现在页面的主标题中,您可以使用以下断言:

1
->assertSelectorTextContains (“html h1.title”“Hello World”);

这个断言检查与CSS选择器匹配的第一个元素是否包含给定的文本。这个断言调用$履带- >过滤器(html h1.title)它允许您使用CSS选择器来过滤页面中的任何HTML元素,并检查其存在,属性,文本等。

assertSelectorTextContains方法不是原生PHPUnit断言,由于WebTestCase类。

爬行程序还可以用于与页面交互。点击一个链接,首先用爬虫选择它,使用XPath表达式或CSS选择器,然后使用客户端点击它:

1 2 3 4 5 6 7 8
链接履带->过滤器(答:包含(“问候”)的//找到所有文本"Greet"的链接->eq (1//选择列表中的第二个链接->链接();//然后点击它履带客户端->点击(链接);

提交表单非常类似:选择一个表单按钮,可选地覆盖一些表单值,并提交相应的表单:

1 2 3 4 5 6 7 8
形式履带->selectButton (“提交”->形式();//设置一些值形式“名字”] =“卢卡斯”形式“form_name(主题)”] =“嘿!”//提交表单履带客户端->提交(形式);

提示

表单还可以处理上传,并包含填充不同类型表单字段的方法(例如。select ()而且蜱虫()).详细信息请参见<一个href="//www.oldmanjams.com/doc/5.0/testing.html" class="reference internal">形式下面的部分。

现在您可以在应用程序中导航,使用断言来测试它实际上执行了您期望的操作。使用爬虫对DOM进行断言:

1 2
//断言响应匹配给定的CSS选择器。->assertGreaterThan (0履带->过滤器(“标题”->count ());

或者直接测试响应内容,如果你只是想断言内容包含一些文本,或者如果响应不是XML/HTML文档:

1 2 3 4
->assertStringContainsString (“Hello World”客户端->getResponse ()->getContent ());

为了让你更快地开始,这里有一个最常见和最有用的测试断言列表:

12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
使用欧宝娱乐app下载地址组件HttpFoundation响应/ /……//声明至少有一个h2标签的类为"subtitle"//第三个参数是一个可选消息,显示在失败的测试中->assertGreaterThan (0履带->过滤器(“h2.subtitle”->count (),“至少有一个副标题”);//断言页面上恰好有4个h2标记->assertCount (4履带->过滤器(“氢气”));//声明"Content-Type"报头为"application/json"->assertResponseHeaderSame (“内容类型”“application / json”);//等价于:->assertTrue (客户端->getResponse ()->->包含(“内容类型”“application / json”));//断言响应内容包含一个字符串->assertStringContainsString (“foo”客户端->getResponse ()->getContent ());/ /……或matches a regex->assertRegExp (' / foo (bar) ?/ '客户端->getResponse ()->getContent ());//断言响应状态代码是2xx->assertResponseIsSuccessful ();//等价于:->assertTrue (客户端->getResponse ()->isSuccessful ());//断言响应状态代码是404 Not Found->assertTrue (客户端->getResponse ()->isNotFound ());//断言一个特定的状态代码->assertResponseStatusCodeSame (201);// HTTP状态值也可以作为常量://例如:201 === Sym欧宝娱乐app下载地址fony\Component\HttpFoundation\Response::HTTP_CREATED . ////等价于:->assertequal (201客户端->getResponse ()->getStatusCode ());//断言响应是重定向到/demo/contact->assertResponseRedirects (“/演示/接触”);//等价于:->assertTrue (客户端->getResponse ()->isRedirect (“/演示/接触”));/ /……或check that the response is a redirect to any URL->assertResponseRedirects ();

使用测试客户端

测试客户端模拟一个HTTP客户端,就像一个浏览器,并向您的Symfony应用程序发出请求:欧宝娱乐app下载地址

1
履带客户端->请求(“得到”' / post / hello world ');

请求()方法将HTTP方法和URL作为参数,并返回一个履带实例。

提示

硬编码请求url是功能测试的最佳实践。如果测试使用Symfony路由器生成url,它将不会检测到对应用程序url欧宝娱乐app下载地址所做的任何可能影响最终用户的更改。

的完整签名请求()方法是:

1 2 3 4 5 6 7 8 9
请求(字符串方法、字符串uri数组参数= [],数组文件= [],数组服务器=[],字符串内容bool,changeHistory真正的

服务器数组是您期望在PHP中通常找到的原始值<一个href="https://www.php.net/manual/en/reserved.variables.server.php" class="reference external" rel="external noopener noreferrer" target="_blank">$ _SERVERsuperglobal。例如,设置内容类型而且推荐人HTTP报头,您将传递以下信息(注意HTTP_非标准标头的前缀):

1 2 3 4 5 6 7 8 9 10
客户端->请求(“得到”' / post / hello world ', [], [], [“CONTENT_TYPE”= >“application / json”“HTTP_REFERER”= >“/ foo / bar”,]);

使用爬虫程序在响应中查找DOM元素。这些元素可以用来点击链接并提交表单:

1 2 3
履带客户端->clickLink (“去别处……”);履带客户端->submitForm (“验证”, (“名字”= >“法”]);

clickLink ()而且submitForm ()方法都返回履带对象。这些方法是浏览应用程序的最佳方式,因为它为您处理了很多事情,比如从表单中检测HTTP方法,并为您提供用于上传文件的漂亮API。

请求()方法也可用于直接模拟表单提交或执行更复杂的请求。一些有用的例子:

12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
//直接提交表单(但是使用爬虫更容易!)客户端->请求(“职位”/提交的, (“名字”= >“法”]);//在请求体中提交原始JSON字符串客户端->请求(“职位”/提交的, [], [], [“CONTENT_TYPE”= >“application / json”),”{“名称”:“法”}’);//表单提交和文件上传使用欧宝娱乐app下载地址组件HttpFoundation文件UploadedFile照片UploadedFile (“/道路/ / photo.jpg”“photo.jpg”“图像/ jpeg”);客户端->请求(“职位”/提交的, (“名字”= >“法”]、[“照片”= >照片]);//执行DELETE请求并传递HTTP报头客户端->请求(“删除”' / post / 12, [], [], [“PHP_AUTH_USER”= >“用户名”“PHP_AUTH_PW”= >“爸爸$ $词”]);

最后但并非最不重要的是,你可以强制每个请求在它自己的PHP进程中执行,以避免在同一个脚本中使用多个客户端时产生任何副作用:

1
客户端->使();

访问容器

强烈建议功能测试只测试响应。但是在某些非常罕见的情况下,您可能希望访问某些服务来编写断言。假设默认情况下服务是私有的,测试类定义了一个属性,该属性存储了一个由Symfony创建的特殊容器,该容器允许获取公共服务和所有未删除的私有服务:欧宝娱乐app下载地址

1 2 3 4 5
//提供对测试中使用的相同服务的访问,除非您正在使用// $client->绝缘()或使用真正的HTTP请求来测试您的应用程序//不要忘记调用self::bootKernel()之前,否则,容器//将为空容器自我:: $容器;

有关应用程序中可用的服务列表,请使用调试:容器命令。

如果私有服务是从来没有在您的应用程序中使用(在测试之外)删除不能从容器中访问,如上面所述。在这种情况下,可以在测验环境并通过该别名访问它:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8
#配置/ services_test.yaml服务:#访问测试中的服务# self:: $容器——> (test.App \ \ SomeTestHelper测试)测试。应用程序\测试\SomeTestHelper:#私有服务的id别名:“应用程序测试\ \ SomeTestHelper”公众:真正的

提示

用于访问私有服务的特殊容器仅存在于测验环境,它本身是一个服务,可以从实际容器中使用test.service_containerid。

提示

如果您需要检查的信息可以从分析器获得,则使用它。

爬虫

每次向客户端发出请求时,都会返回一个爬虫实例。它允许您遍历HTML文档,选择节点,查找链接和表单。

形式

使用submitForm ()方法提交包含给定按钮的表单:

1 2 3 4 5 6
客户端静态::createClient ();客户端->请求(“得到”' / post / hello world ');履带客户端->submitForm (“添加评论”, (comment_form[内容]= >“……”]);

的第一个参数submitForm ()是文本内容,id价值的名字任何< >按钮< input type = " submit " >包括在表格中。第二个可选参数用于覆盖默认的表单字段值。

请注意

注意,您选择的是表单按钮而不是表单,因为一个表单可以有几个按钮;如果使用遍历API,请记住必须寻找按钮。

如果您需要访问<一个href="https://github.com/symfony/symfony/blob/5.0/src/Symfony/Component/DomCrawler/Form.php" class="reference external" title="形式" rel="external noopener noreferrer" target="_blank">形式对象,该对象提供特定于表单的有用方法(例如getUri ()getvalue ()而且getFields ())使用selectButton ()方法:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
客户端静态::createClient ();履带客户端->请求(“得到”' / post / hello world ');buttonCrawlerNode履带->selectButton (“提交”);//选择包含此按钮的表单形式buttonCrawlerNode->形式();//你也可以传递一个覆盖默认值的字段值数组形式buttonCrawlerNode->形式([my_form[名称]= >“法”“my_form(主题)”= >“欧宝娱乐app下载地址Symfony岩石!”]);//你可以传递第二个参数来覆盖表单HTTP方法形式buttonCrawlerNode->形式([],“删除”);//提交表单对象客户端->提交(形式);

属性的第二个参数传递字段值提交()方法:

1 2 3 4
客户端->提交(形式, (my_form[名称]= >“法”“my_form(主题)”= >“欧宝娱乐app下载地址Symfony岩石!”]);

对于更复杂的情况,请使用形式实例作为数组单独设置每个字段的值:

1 2 3
//改变字段的值形式my_form[名称]] =“法”形式“my_form(主题)”] =“欧宝娱乐app下载地址Symfony岩石!”

还有一个很好的API来根据字段的类型来操作字段的值:

12 3 4 5 6 7 8 9 10 11 12
//选择一个选项或收音机形式“国家”->选择(“法国”);//勾选复选框形式“like_欧宝娱乐app下载地址symfony”->蜱虫();//上传文件形式“照片”->上传(“/道路/ / lucas.jpg”);//如果是多个文件上传形式“my_form[领域][O]->上传(“/道路/ / lucas.jpg”);形式“my_form(领域)[1]”->上传(“/道路/ / lisa.jpg”);

提示

而不是硬编码表单名称作为字段名称的一部分(例如;my_form[…]在前面的示例中),可以使用<一个href="https://github.com/symfony/symfony/blob/5.0/src/Symfony/Component/DomCrawler/Form.php" class="reference external" title="getName ()" rel="external noopener noreferrer" target="_blank">getName ()方法获取表单名称。

提示

如果您有意选择“无效”的选择/单选值,请参见<一个href="//www.oldmanjams.com/doc/5.0/components/dom_crawler.html" class="reference internal">DomCrawler组件

提示

方法可以获得将要提交的值getvalue ()方法。形式对象。返回的单独数组中有上传的文件getfile ().的getPhpValues ()而且getPhpFiles ()方法也会返回提交的值,但是是PHP格式(它转换了带有方括号符号的键)。my_form(主题)- PHP数组)。

提示

提交()而且submitForm ()方法定义可选参数,在提交表单时添加自定义服务器参数和HTTP报头:

1 2
客户端->提交(形式, [], [“HTTP_ACCEPT_LANGUAGE”= >“西文”]);客户端->submitForm (按钮[],“职位”, (“HTTP_ACCEPT_LANGUAGE”= >“西文”]);

向集合中添加和删除表单

如果你使用<一个href="//www.oldmanjams.com/doc/5.0/form/form_collections.html" class="reference internal">收集表格,不能将字段添加到现有表单$form['task[tags][0][name]'] = 'foo';.这将导致一个错误无法到达的字段“…”因为美元的形式只能用于设置现有字段的值。为了添加新的字段,你必须将值添加到原始数据数组:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16
//获取表单形式履带->过滤器(“按钮”->形式();//获取原始值形式->getPhpValues ();//添加字段到原始值“任务”] [“标签”] [0] [“名字”] =“foo”“任务”] [“标签”] [1] [“名字”] =“酒吧”//提交包含现有值和新值的表单履带客户端->请求(形式->getMethod (),形式->getUri (),形式->getPhpFiles ());// 2个标签被添加到集合中->assertequal (2履带->过滤器(ul。标签> li'->count ());

在哪里任务[标记][0][名称]是用JavaScript创建的字段的名称。

你可以删除一个现有的字段,例如一个标签:

12 3 4 5 6 7 8 9 10 11 12
//获取表单的值形式->getPhpValues ();//删除第一个标记设置“任务”] [“标签”] [0]);//提交数据履带客户端->请求(形式->getMethod (),形式->getUri (),形式->getPhpFiles ());//标签已被删除->assertequal (0履带->过滤器(ul。标签> li'->count ());

测试配置

功能测试使用的客户端创建在特殊环境中运行的内核测验环境。因为Symf欧宝娱乐app下载地址ony加载配置/包/测试/ * .yaml测验环境,您可以调整应用程序的任何设置专门用于测试。

例如,默认情况下,Swift Mailer配置为实际上是在测验环境。你可以看到这个在swiftmailer配置选项:

  • YAML
  • XML
  • PHP
1 2 3 4 5
#配置/包/测试/ swiftmailer.yaml#……swiftmailer:disable_delivery:真正的

您也可以完全使用不同的环境,或重写默认的调试模式(真正的),将它们作为选项传递给createClient ()方法:

1 2 3 4
客户端静态::createClient ([“环境”= >“my_test_env”“调试”= >]);
此工作,包括代码示例,是根据<一个rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/">创作共用BY-SA 3.0许可证。