测试

测试

当我们开始向应用程序添加越来越多的功能时,可能是时候讨论测试了。

有趣的事实:我在编写本章的测试时发现了一个bug。

ob娱乐下载Symfony依靠PHPUnit进行单元测试。让我们来安装它:

1
ob娱乐下载Symfony作曲家req phpunit—dev

编写单元测试

SpamChecker是我们要为之编写测试的第一个类。生成一个单元测试:

1
ob娱乐下载Symfony控制台制作:测验TestCase SpamCheckerTest

测试SpamChecker是一个挑战,因为我们当然不想击中Akismet API。我们将要模拟API。

让我们写一个API返回错误的第一个测试:

12 3 4 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
——/测试/ SpamCheckerTest.php+ + + b /测试/ SpamCheckerTest.php@@ -2,12 +2,26 @@名称空间的应用程序\测试;+使用App \实体\评论;+使用App \ SpamChecker;使用PHPUnit) \ Framework \ TestCase;+使用Syob娱乐下载mfony \ \ HttpClient \ MockHttpClient组件;+使用Syob娱乐下载mfony \组件\ HttpClient \ \ MockResponse反应;+使用Syob娱乐下载mfony \ \ HttpClient \ ResponseInterface合同;类SpamCheckerTest扩展TestCase {—公共函数testSomething(): void+公共函数testSpamScoreWithInvalidRequest(): void- $ this - > assertTrue(真正的);+ $comment = new comment ();+ $评论- > setCreatedAtValue ();+ $context = [];++ $client = new MockHttpClient([new MockResponse('invalid', ['response_headers' => ['x-akismet-debug-help: invalid key']])]);+ $checker = new SpamChecker($client, 'abcde');++ $ this - > expectException (\ RuntimeException::类);+ $this->expectExceptionMessage('无法检查垃圾邮件:无效(无效键).');+ $checker->getSpamScore($comment, $context);}}

MockHttpClient类使得模拟任何HTTP服务器成为可能。它需要一个数组MockResponse包含预期正文和响应标头的实例。

然后,我们调用getSpamScore ()方法,并检查是否通过expectException ()PHPUnit方法。

运行测试以检查它们是否通过:

1
ob娱乐下载Symfony PHP bin/phpunit

让我们为快乐路径添加测试:

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
——/测试/ SpamCheckerTest.php+ + + b /测试/ SpamCheckerTest.php@@ -24,4 +24,32 @@类SpamCheckerTest扩展TestCase $this->expectExceptionMessage('无法检查垃圾邮件:无效(无效键).');检查器- > getSpamScore(评论,上下文美元);}++ / * *+ * @dataProvider getComments+ * /+公共函数testSpamScore(int $expectedScore, ResponseInterface $response, Comment $ Comment, array $context)+ {+ $client =新的MockHttpClient([$response]);+ $checker = new SpamChecker($client, 'abcde');++ $score = $checker->getSpamScore($comment, $context);+ $this->assertSame($expectedScore, $score);+}++公共函数getComments():可迭代+ {+ $comment = new comment ();+ $评论- > setCreatedAtValue ();+ $context = [];++ $response = new MockResponse(", ['response_headers' => ['x-akismet-pro-tip: discard']]);+ yield 'blatant_spam' => [2, $response, $comment, $context];++ $response =新的MockResponse('true');+ yield 'spam' => [1, $response, $comment, $context];++ $response =新的MockResponse('false');+ yield 'ham' => [0, $response, $comment, $context];+}

PHPUnit数据提供者允许我们为几个测试用例重用相同的测试逻辑。

为控制器编写功能测试

测试控制器与测试“常规”PHP类有点不同,因为我们希望在HTTP请求的上下文中运行它们。

为会议控制器创建一个功能测试:

测试/控制器/ ConferenceControllerTest.php
12 3 4 5 6 7 8 9 10 11 12 13 14 15
名称空间应用程序测试控制器使用ob娱乐下载FrameworkBundle测试WebTestCaseConferenceControllerTest扩展WebTestCase公共函数testIndex()客户端静态::createClient ();客户端->请求(“得到”' / ');->assertResponseIsSuccessful ();->assertSelectorTextContains (“氢气”“给出你的反馈”);}}

使用ob娱乐下载\包\ FrameworkBundle\测试\ WebTestCase而不是PHPUnit) \ \ TestCase的框架作为测试的基类,它为功能测试提供了一个很好的抽象。

美元的客户变量模拟浏览器。但是,它不向服务器发出HTTP调用,而是直接调用Symfony应用程序。ob娱乐下载这种策略有几个好处:它比客户端和服务器之间的往返要快得多,但它还允许测试在每个HTTP请求之后自检服务的状态。

第一个测试检查主页是否返回一个200 HTTP响应。

断言,例如assertResponseIsSuccessful添加在PHPUnit的顶部,以简化您的工作。Symfony定义了许多这样的断言。ob娱乐下载

提示

我们用过/而不是通过路由器生成URL。这样做是有目的的,因为测试最终用户url是我们想要测试的一部分。如果你改变了路由路径,测试将会中断,这是一个很好的提醒,你应该将旧的URL重定向到新的URL,以更好地处理链接回你网站的搜索引擎和网站。

配置测试环境

默认情况下,PHPUnit测试在测验ob娱乐下载PHPUnit配置文件中定义的Symfony环境:

phpunit.xml.dist
1 2 3 4 5 6 7 8 9
<phpunit)><php><ini的名字“error_reporting”价值“1”/><服务器的名字“APP_ENV”价值“测试”“真正的”/><服务器的名字“SHELL_VERBOSITY”价值“1”/><服务器的名字“ob娱乐下载SYMFONY_PHPUNIT_REMOVE”价值""/><服务器的名字“ob娱乐下载SYMFONY_PHPUNIT_VERSION”价值“8.5”/>php>phpunit)>

要使测试正常工作,必须设置AKISMET_KEY这个秘密测验环境:

1
ob娱乐下载Symfony控制台的秘密:AKISMET_KEY——env =测验

使用测试数据库

正如我们已经看到的,Symfony CLI自动公开ob娱乐下载DATABASE_URL环境变量。当APP_ENV测验,像设置时运行PHPUnit,数据库名称从主要main_test这样测试就有了自己的数据库。这是非常重要的,因为我们需要一些稳定的数据来运行我们的测试,我们当然不想覆盖我们在开发数据库中存储的数据。

在能够运行测试之前,我们需要“初始化”测验数据库(创建数据库并迁移它):

1 2
ob娱乐下载Symfony控制台原则:database:create——env=测验ob娱乐下载Symfony控制台原则:迁移:migrate -n——env=测验

在Linux和类似的操作系统上,您可以使用APP_ENV =刺激而不是——env =刺激

1
APP_ENV=prod ob娱乐下载symfony控制台原则:数据库:创建

如果现在运行测试,PHPUnit将不再与开发数据库交互。若要只运行新测试,请将路径传递到它们的类路径:

1
ob娱乐下载symfony php bin/phpunit tests/Controller/ConferenceControllerTest.php

提示

当测试失败时,自省Response对象可能会很有用。通过客户端- > getResponse ()而且回声看看它是什么样子。

定义设备

为了能够测试评论列表、分页和表单提交,我们需要用一些数据填充数据库。我们希望测试运行之间的数据相同,以使测试通过。固定装置正是我们所需要的。

安装Doctrine fixture包:

1
ob娱乐下载Symfony作曲家需要orm-fixture—dev

一个新的src / DataFixtures /目录已经在安装过程中使用示例类创建,可以进行自定义。现在增加两个会议和一个评论:

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
——/ src / DataFixtures / AppFixtures.php+ + + b / src / DataFixtures / AppFixtures.php@@ -2,6 +2,8 @@名称空间的应用程序\ DataFixtures;+使用App \实体\评论;+使用App \实体\会议;使用原则\包\ FixturesBundle \夹具;使用原则\ \ ObjectManager持久性;@@ -9,8 +11,24 @@类AppFixtures扩展Fixture{公共函数加载(ObjectManager $manager):无效{- // $product = new product ();- // $manager->persist($product);+ $amsterdam =新会议();+ $阿姆斯特丹- > setCity(阿姆斯特丹);+ $阿姆斯特丹- > setYear (' 2019 ');+ $阿姆斯特丹- > setIsInternational(真正的);+ $经理- >保存(阿姆斯特丹);++ $paris = new Conference();+ $巴黎- > setCity(巴黎);+ $巴黎- > setYear (' 2020 ');+ $巴黎- > setIsInternational(假);+ $经理- >保存(巴黎);++ $comment1 = new Comment();+ $ comment1 - > setConference阿姆斯特丹($);+ $ comment1 - > setAuthor(“法”);+ $ comment1 - > setEmail (fabien@example.com);+ $comment1->setText('This was a great conference.');+ $经理- >保存($ comment1);经理- >冲洗();}

当我们加载夹具时,所有数据将被删除;包括admin用户。为了避免这种情况,让我们在fixture中添加admin用户:

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
——/ src / DataFixtures / AppFixtures.php+ + + b / src / DataFixtures / AppFixtures.php@@ -2,13 +2,22 @@名称空间的应用程序\ DataFixtures;+使用App \实体\管理;使用App \实体\评论;使用App \实体\会议;使用原则\包\ FixturesBundle \夹具;使用原则\ \ ObjectManager持久性;+使用Syob娱乐下载mfony \组件\ PasswordHasher \切肉机\ PasswordHasherFactoryInterface;类AppFixtures扩展Fixture {+ private $passwordHasherFactory;++公共函数__construct(PasswordHasherFactoryInterface $encoderFactory)+ {+ $this->passwordHasherFactory = $encoderFactory;+}+public function load(ObjectManager $manager): void {$amsterdam = new Conference();@@ -30,6 +39,12 @@类AppFixtures extends Fixture $comment1->setText('这是一个伟大的会议。');经理- >保存($ comment1);+ $admin = new admin ();+ $管理- > setRoles ([' ROLE_ADMIN ']);+ $管理- > setUsername(管理);+ $admin->setPassword($this->passwordHasherFactory->getPasswordHasher(admin::class)->hash('admin', null));+ $经理- >保存(管理);+经理- >冲洗();}}

提示

如果不记得对于给定的任务需要使用哪个服务,请使用调试:自动装配用一些关键字:

1
ob娱乐下载Symfony控制台调试:自动装配编码器

加载装置

加载的夹具测验环境/数据库:

1
ob娱乐下载Symfony控制台原则:fixture:load——env=测验

在功能测试中爬行网站

正如我们所看到的,测试中使用的HTTP客户端模拟浏览器,因此我们可以像使用无头浏览器一样浏览网站。

添加一个新的测试,从主页点击会议页面:

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21 22
——/ /控制器/ ConferenceControllerTest.php测试+ + + b /测试/控制器/ ConferenceControllerTest.php@@ -14,4 +14,19 @@类ConferenceControllerTest扩展WebTestCase $this->assertResponseIsSuccessful();$this->assertSelectorTextContains('h2', '给你的反馈');}++公共函数testConferencePage()+ {+ $client = static::createClient();+ $crawler = $client->request('GET', '/');++ $this->assertCount(2, $爬虫->过滤器('h4'));++客户端- > clickLink(“视图”);++ $ this - > assertPageTitleContains(阿姆斯特丹);+ $ this - > assertResponseIsSuccessful ();+ $this->assertSelectorTextContains('h2', '阿姆斯特丹2019');+ $this->assertSelectorExists('div:contains("有1个注释")');+}

让我们用简单的英语来描述一下这次考试的情况:

  • 就像第一次测试一样,我们进入主页;
  • 请求()方法返回履带帮助查找页面上元素的实例(如链接、表单或任何可以通过CSS选择器或XPath找到的东西);
  • 多亏了CSS选择器,我们断言主页上列出了两个会议;
  • 然后点击“View”链接(因为它不能同时点击多个链接,Symfony会自动选择它找到的第一个链接);ob娱乐下载
  • 我们断言页面标题、响应和页面< h2 >为了确保我们在正确的页面上(我们也可以检查匹配的路由);
  • 最后,我们断言页面上有1条注释。div:包含()不是一个有效的CSS选择器,但Symfony有一些很好的补充,借鉴ob娱乐下载jQuery。

而不是点击文本(即。视图),我们也可以通过CSS选择器选择链接:

1
客户端->点击(履带->过滤器('h4 + p a'->链接());

检查新测试是否为绿色:

1
ob娱乐下载symfony php bin/phpunit tests/Controller/ConferenceControllerTest.php

在功能测试中提交表单

你想更上一层楼吗?尝试通过模拟表单提交在测试中的会议上添加带有照片的新注释。这看起来雄心勃勃,不是吗?看看需要的代码:不会比我们已经写的更复杂:

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21 22
——/ /控制器/ ConferenceControllerTest.php测试+ + + b /测试/控制器/ ConferenceControllerTest.php@@ -29,4 +29,19 @@ class ConferenceControllerTest extends WebTestCase $this->assertSelectorTextContains('h2', 'Amsterdam 2019');$this->assertSelectorExists('div:contains("有1个注释")');}++公共函数testCommentSubmission()+ {+ $client = static::createClient();+ $client->request('GET', '/conference/amsterdam-2019');+ $client->submitForm('提交',[+ 'comment_form[author]' => 'Fabien',+ 'comment_form[text]' => '自动功能测试的一些反馈',+ 'comment_form[email]' => 'me@automat.ed',+ 'comment_form[photo]' => dirname(__DIR__, 2).'/public/images/under-construction.gif',+));+ $ this - > assertResponseRedirects ();+客户端- > followRedirect ();+ $this->assertSelectorExists('div:contains("有2个注释")');+}

提交表格submitForm (),通过浏览器DevTools或通过Symfony Profiler Form面板找到输入名称。ob娱乐下载注意,巧妙地重新利用了施工中的形象!

再次运行测试,检查是否一切正常:

1
ob娱乐下载symfony php bin/phpunit tests/Controller/ConferenceControllerTest.php

如果要在浏览器中检查结果,请停止Web服务器并重新运行测验环境:

1 2
ob娱乐下载symfony服务器:停止ob娱乐下载Symfony服务器:start -d——env=测验
/会议/阿姆斯特丹- 2019

重新装载装置

如果您再次运行测试,它们应该会失败。由于现在数据库中有更多的注释,检查注释数量的断言被破坏了。我们需要在每次运行之前通过重新加载fixture来重置数据库的状态:

1 2
ob娱乐下载Symfony控制台原则:fixture:load——env=测验ob娱乐下载symfony php bin/phpunit tests/Controller/ConferenceControllerTest.php

使用Makefile自动化您的工作流

必须记住一系列命令来运行测试是很烦人的。这至少应该被记录下来。但是文件欧宝官网下载app应该是最后的手段。相反,如何自动化日常活动呢?这将作为文档,帮助其他开发人员发现,并使欧宝官网下载app开发人员的生活更容易和更快。

使用一个Makefile是自动化命令的一种方法:

Makefile
1 2 3 4 5 6 7 8 9
SHELL:= /bin/bash测试:ob娱乐下载Symfony控制台原则:database:drop——force——env=test || true Symfony控制台原则:database:create——env=test Symfony控制台原则:migrations:migrate -n——env=test Symfony控制台原则:fixture:load -n——env=test Symfony PHP bin/phpunit@.PHONY:测试

警告

在Makefile规则中,缩进必须由单个制表符组成,而不是空格。

注意- n条令上的标志;它是Symfony命令上的一个全局标志,使它们ob娱乐下载不具有交互性。

当您希望运行测试时,请使用做测试

1
做测试

在每次测试后重置数据库

在每次测试运行后重置数据库很好,但是拥有真正独立的测试就更好了。我们不希望一次测试依赖于前几次测试的结果。改变测试的顺序不应该改变结果。正如我们现在要弄清楚的,现在不是这样的。

移动testConferencePage之后的测试testCommentSubmission一:

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
——/ /控制器/ ConferenceControllerTest.php测试+ + + b /测试/控制器/ ConferenceControllerTest.php@@ -15,21 +15,6 @@ class ConferenceControllerTest extends WebTestCase $this->assertSelectorTextContains('h2', '给出您的反馈');}-公共函数testConferencePage()——{- $client = static::createClient();- $crawler = $client->request('GET', '/');-- $this->assertCount(2, $爬虫->过滤器('h4'));--客户- > clickLink美元(“视图”);-- $ this - > assertPageTitleContains(阿姆斯特丹);- $ this - > assertResponseIsSuccessful ();- $this->assertSelectorTextContains('h2', '阿姆斯特丹2019');- $this->assertSelectorExists('div:contains("有1条评论")');- - - - - -}-公共函数testCommentSubmission() {$client = static::createClient();@@ -44,4 +29,19 @@ class ConferenceControllerTest extends WebTestCase $client->followRedirect();$this->assertSelectorExists('div:contains("有2个注释")');}++公共函数testConferencePage()+ {+ $client = static::createClient();+ $crawler = $client->request('GET', '/');++ $this->assertCount(2, $爬虫->过滤器('h4'));++客户端- > clickLink(“视图”);++ $ this - > assertPageTitleContains(阿姆斯特丹);+ $ this - > assertResponseIsSuccessful ();+ $this->assertSelectorTextContains('h2', '阿姆斯特丹2019');+ $this->assertSelectorExists('div:contains("有1个注释")');+}

测试现在失败。

要在测试之间重置数据库,请安装DoctrineTestBundle:

1
ob娱乐下载Symfony作曲家配置extra.symfony.allow-contrib真正的
1
ob娱乐下载交响乐作曲家要求“dama / doctrine-test-bundle: ^ 6”——开发

你需要确认配方的执行(因为它不是一个“官方”支持的包):

1 2 3 4 5 6 7 8 9 10 11
ob娱乐下载Symfony操作:1 recipe (a5c79a9ff21bc3ae26d9bb25f1262ed7) - WARNING dama/doctrin -test-bundle (>=4.0): From github.com/symfony/recipes-contrib:master此包的recipe来自“contrib”存储库,该存储库向社区开放。欧宝体育平台怎么样在https://github.com/symfony/recipes-contob娱乐下载rib/tree/master/dama/doctrine-test-bundle/4.0上查看食谱,你想要执行这个食谱吗?[y]是[n]否[a]对所有包都是,仅对当前安装会话是[p]永久是,永远不再要求此项目(默认为n): p

启用PHPUnit监听器:

12 3 4 5 6 7 8 9 10 11 12 13
——/ phpunit.xml.dist+ + + b / phpunit.xml.dist@@ -29,6 +29,10 @@< /包括> < / >报道+ <扩展>+ + < /扩展>+   .

和完成。在测试中所做的任何更改现在都会在每个测试结束时自动回滚。

测试应该再次显示为绿色:

1
做测试

使用真正的浏览器进行功能测试

功能测试使用直接调用Symfony层的特殊浏览器。ob娱乐下载但是你也可以使用一个真正的浏览器和真正的HTTP层,这要感谢Symfony Panther:ob娱乐下载

1
ob娱乐下载Symfony作曲家req panther—dev

然后,通过以下更改,您可以使用真正的谷歌Chrome浏览器编写测试:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
——/ /控制器/ ConferenceControllerTest.php测试+ + + b /测试/控制器/ ConferenceControllerTest.php@@ -2,13 +2,13 @@名称空间应用\ \测试控制器;用Symfob娱乐下载ony \包\ FrameworkBundle \ \ WebTestCase测试;+使用Syob娱乐下载mfony \ \豹\ PantherTestCase组件;-class ConferenceControllerTest扩展WebTestCase+类ConferenceControllerTest扩展PantherTestCase{公共函数testIndex() {- $client = static::createClient();+ $client = static::createPantherClient(['external_base_uri' => $_SERVER['ob娱乐下载SYMFONY_PROJECT_DEFAULT_ROUTE_URL']]);客户端- >请求(‘得到’,‘/’);$ this - > assertResponseIsSuccessful ();

ob娱乐下载SYMFONY_PROJECT_DEFAULT_ROUTE_URL环境变量包含本地web服务器的URL。

选择正确的测试类型

到目前为止,我们已经创建了三种不同类型的测试。虽然我们只使用了maker包来生成单元测试类,但我们也可以使用它来生成其他测试类:

1 2 3
ob娱乐下载Symfony控制台制作:测验\ \ ConferenceController WebTestCase控制器ob娱乐下载Symfony控制台制作:测验\ \ ConferenceController PantherTestCase控制器

maker包支持生成以下类型的测试,具体取决于您想如何测试应用程序:

  • TestCase:基本PHPUnit测试;
  • KernelTestCase:可以访问Symfony服务的基本测试;ob娱乐下载
  • WebTestCase:运行类似浏览器的场景,但不执行JavaScript代码;
  • ApiTestCase:运行面向api的场景;
  • PantherTestCase:使用真实浏览器或HTTP客户端和真实web服务器运行端到端场景。

使用Blackfire运行黑盒功能测试

运行功能测试的另一种方法是使用黑焰的球员.除了功能测试之外,它还可以执行性能测试。

读了性能步骤了解更多。

此工作,包括代码示例,是根据知识共享协议BY-NC-SA 4.0许可证。