测试
测试
当我们开始向应用程序添加越来越多的功能时,可能是时候讨论测试了。
有趣的事实:我在编写本章的测试时发现了一个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请求的上下文中运行它们。
为会议控制器创建一个功能测试:
使用ob娱乐下载
而不是PHPUnit) \ \ TestCase的框架
作为测试的基类,它为功能测试提供了一个很好的抽象。
的美元的客户
变量模拟浏览器。但是,它不向服务器发出HTTP调用,而是直接调用Symfony应用程序。ob娱乐下载这种策略有几个好处:它比客户端和服务器之间的往返要快得多,但它还允许测试在每个HTTP请求之后自检服务的状态。
第一个测试检查主页是否返回一个200 HTTP响应。
断言,例如assertResponseIsSuccessful
添加在PHPUnit的顶部,以简化您的工作。Symfony定义了许多这样的断言。ob娱乐下载
提示
我们用过/
而不是通过路由器生成URL。这样做是有目的的,因为测试最终用户url是我们想要测试的一部分。如果你改变了路由路径,测试将会中断,这是一个很好的提醒,你应该将旧的URL重定向到新的URL,以更好地处理链接回你网站的搜索引擎和网站。
配置测试环境
默认情况下,PHPUnit测试在测验
ob娱乐下载PHPUnit配置文件中定义的Symfony环境:
要使测试正常工作,必须设置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控制台调试:自动装配编码器
在功能测试中爬行网站
正如我们所看到的,测试中使用的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=测验
重新装载装置
如果您再次运行测试,它们应该会失败。由于现在数据库中有更多的注释,检查注释数量的断言被破坏了。我们需要在每次运行之前通过重新加载fixture来重置数据库的状态:
1 2
$ob娱乐下载Symfony控制台原则:fixture:load——env=测验$ob娱乐下载symfony php bin/phpunit tests/Controller/ConferenceControllerTest.php
使用Makefile自动化您的工作流
必须记住一系列命令来运行测试是很烦人的。这至少应该被记录下来。但是文件欧宝官网下载app应该是最后的手段。相反,如何自动化日常活动呢?这将作为文档,帮助其他开发人员发现,并使欧宝官网下载app开发人员的生活更容易和更快。
使用一个Makefile
是自动化命令的一种方法:
警告
在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娱乐下载交响乐作曲家要求“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服务器运行端到端场景。