Symfony 2.8 ltsでブログを作成する[パート6]






Githubプロジェクト
必要なマニュアルの一部をインストールする方法については、 リンクでリポジトリの説明を参照してください 。 (たとえば、前のレッスンを経ずにこのレッスンから始めたい場合)


Symfony2でのテスト

PHPUnitは、PHPでテストを記述するための「事実上の標準」になっているため、PHPUnitを学習することは、すべてのPHPプロジェクトで役立ちます。 また、このパートで扱うトピックのほとんどは言語に依存しないため、使用する他の言語に適用できることを忘れないでください。

ヒント

独自のSymfony2オープンソースバンドルを作成する予定の場合、バンドルが十分にテスト(および文書化)されていれば、ユーザーから良い反応を得る可能性がはるかに高くなります。 knpbundlesで利用可能な既存のsymfony2バンドルのリストを見てください


単体テスト


単体テストは、単独で使用した場合に個々の機能ユニットの正しい動作を検証します。 Symfony2のように、オブジェクト指向のコードでは、モジュールはクラスとそのメソッドです。 たとえば、BlogおよびCommentエンティティクラスのテストを作成できます。 単体テストを作成する場合、テストは他のテストとは無関係に作成する必要があります。つまり、テストBの結果は結果Aに依存するべきではありません 単体テストを使用すると、外部依存関係を持つ関数をテストできるダミーオブジェクトを作成できます。 架空のオブジェクト(Moki)を使用すると、実際の実行の代わりに関数呼び出しをシミュレートできます。 この例は、外部APIをラップするクラスのユニットテストです。 APIクラスは、トランスポート層プロトコルを使用して外部APIと通信できます。 実際に外部APIから返すのではなく、ダミーのトランスポートレベルのリクエストメソッドを作成して、設定した結果を返すことができます。 次のセクションで示すように、単体テストでは、アプリケーションのコンポーネントが一緒に機能することを確認しません。

機能テスト


機能テストでは、ルーティング、コントローラー、マッピングなどのさまざまなアプリケーションコンポーネントの統合を検証します。 機能テストは、ブラウザで実行できる手動テストに似ています。たとえば、メインページの要求、レコードのリンクのクリック、表示の正確性の確認などです。 機能テストにより、このプロセスを自動化できます。 Symfony2には、ページリクエスト、フォームの送信、クライアントからの応答をバイパスするために使用できるクローラーDOMを実行できるClientなど、機能テストに役立つ多くの便利なクラスが付属しています。

Phpunit


前述のように、Symfony2テストはPHPUnitを使用して記述されています。 この部分からテストを実行するには、PHPUnitをインストールする必要があります。 インストールの詳細については、PHPUnit Webサイトの公式ドキュメントを参照してください。 Symfony2でテストを実行するには、PHPUnit 5.4をインストールする必要があります(PHP 5.6が必要です)。 PHPUnitは非常に大きなテストライブラリです。この接続では、追加の情報が必要になる可能性のある公式ドキュメントへのリンクが作成されます。

アサーション


テストを書くことは、予想されるテスト結果が実際の結果と等しいかどうかのテストです。 PHPUnitには、このタスクを支援する多くのアサーションメソッドがあります。 使用する一般的なアサーションメソッドの一部を以下にリストします。

// Check 1 === 1 is true $this->assertTrue(1 === 1); // Check 1 === 2 is false $this->assertFalse(1 === 2); // Check 'Hello' equals 'Hello' $this->assertEquals('Hello', 'Hello'); // Check array has key 'language' $this->assertArrayHasKey('language', array('language' => 'php', 'size' => '1024')); // Check array contains value 'php' $this->assertContains('php', array('php', 'ruby', 'c++', 'JavaScript')); 


アサーションの完全なリストは、 PHPUnitのドキュメントにあります。

Symfony2テストの実行


テストの作成を始める前に、Symfony2でテストを実行する方法を見てみましょう。 ユニットは構成ファイルを使用できます。 Symfony2プロジェクトでは、このファイルはapp / phpunit.xml.distにあります。 このファイルには接尾辞.distが付いているため 、その内容をapp / phpunit.xmlというファイルにコピーする必要があります。

ヒント

GitなどのVCSを使用している場合は、 app / phpunit.xmlファイルを無視リストに追加する必要があります


PHPUnit構成ファイルの内容を見ると、次のことがわかります。

 <!-- app/phpunit.xml --> <testsuites> <testsuite name="Project Test Suite"> <directory>../src/*/*Bundle/Tests</directory> <directory>../src/*/Bundle/*Bundle/Tests</directory> </testsuite> </testsuites> 


これらのオプションは、テストスイートの一部であるいくつかのディレクトリを構成します。 起動すると、 PHPUnitは上記のディレクトリで実行するテストを探します。 コマンドラインから追加の引数を渡して、特定のディレクトリでPHPUnitテストを実行することもできます。 後でこれを実現する方法がわかります。

ヒント

XMLファイルを使用したPHPUnitの構成の詳細については、 PHPUnitのドキュメントを参照してください。


現在のテストの実行


Symfony2ジェネレーターコマンドの1つを使用して最初の部分でBlogger BlogBu​​ndleを作成したため、彼女はDefault Controllerクラスのコントローラーテストも作成しました。 プロジェクトのルートディレクトリから次のコマンドを実行して、このテストを実行できます。 -cオプションは、PHPUnitがappディレクトリから設定をロードする必要があることを示します。
 $ phpunit -c app 


テストが完了すると、テストが失敗したことが通知されます。 src / Blogger / BlogBu​​ndle / Tests / Controller / DefaultControllerTest.phpにあるDefaultControllerTestクラスを見ると、
次のコンテンツ
 <?php namespace Blogger\BlogBundle\Tests\Controller; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class DefaultControllerTest extends WebTestCase { public function testIndex() { $client = static::createClient(); $crawler = $client->request('GET', '/'); $this->assertContains('Hello World', $client->getResponse()->getContent()); } } 



これは、Symfony2が生成したデフォルトコントローラークラスの機能テストです。 パート1で覚えている場合、このコントローラーにはリクエストを処理するメソッドがありました/このアドレスで、 「Hello World」の内容を持つテンプレートを表示しました。 このコントローラーを削除し、このルートのテンプレートの内容がまったく異なるため、上記のテストは失敗します。
機能テストはこの章の大部分であり、後で詳しく説明します。
Default Controllerクラスが削除されたため、 src / Blogger / BlogBu​​ndle / Tests / Controller / DefaultControllerTest.phpファイルを削除できます

単体テスト


前に説明したように、ユニットテストとは、アプリケーションの個々のユニットを個別にテストすることです。 単体テストを作成するときは、テストフォルダーにバンドルの構造を複製することをお勧めします。 たとえば、 src / Blogger / BlogBu​​ndle / Entity / Blog.phpにあるBlogクラスエンティティをテストする場合テストファイルはsrc / Blogger / BlogBu​​ndle / Tests / Entity / BlogTest.phpにあります。 例は次のようになります
次のように
 src/Blogger/BlogBundle/ Entity/ Blog.php Comment.php Controller/ PageController.php Twig/ Extensions/ BloggerBlogExtension.php Tests/ Entity/ BlogTest.php CommentTest.php Controller/ PageControllerTest.php Twig/ Extensions/ BloggerBlogExtensionTest.php 



各テストファイルには接尾辞Testが付いていることに注意してください。

ブログエンティティテスト-slugifyメソッド


Blogエンティティでslugifyメソッドのテストを開始します。 このメソッドが正しく機能することを確認するためのテストを作成しましょう。 にある新しいファイルを作成します
src / Blogger / BlogBu​​ndle / Tests / Entity / BlogTest.php
 <?php // src/Blogger/BlogBundle/Tests/Entity/BlogTest.php namespace Blogger\BlogBundle\Tests\Entity; use Blogger\BlogBundle\Entity\Blog; class BlogTest extends \PHPUnit_Framework_TestCase { } 



Blogエンティティのテストクラスを作成しました。 ファイルの場所は、上記のフォルダー構造に従うことに注意してください。 Blog Testクラスは、基本PHPUnitクラスPHPUnit_Framework_TestCaseを拡張します。 PHPUnit用に記述するすべてのテストは、このクラスの子孫になります。 クラスは共通のPHP名前空間で宣言されているため、前の部分から、クラス名PHPUnit_Framework_TestCaseの前に\を配置する必要があることを覚えています。

Blogエンティティテストのクラススケルトンができました。テストを作成しましょう。 PHPUnitのテストは、 testSlugify()など、テストプレフィックス付きのTestクラスのメソッドです。 BlogTestを更新します
src / Blogger / BlogBu​​ndle / Tests / Entity / BlogTest.php
 // src/Blogger/BlogBundle/Tests/Entity/BlogTest.php // .. class BlogTest extends \PHPUnit_Framework_TestCase { public function testSlugify() { $blog = new Blog(); $this->assertEquals('hello-world', $blog->slugify('Hello World')); } } 



これは非常に簡単なテストです。 新しいBlogエンティティを作成し、slugifyメソッドの結果に対してassertEquals()を実行します。 assertEquals()メソッドは、2つの必須引数、予期される結果と実際の結果を取ります。 オプションの3番目の引数を渡して、テストが失敗したときにメッセージを表示できます。

新しい単体テストを実行しましょう。 コンソールで次のコマンドを入力します。

 $ phpunit -c app 


以下が表示されます。

 PHPUnit 5.4.6 by Sebastian Bergmann and contributors. . 1 / 1 (100%) Time: 348 ms, Memory: 13.25MB OK (1 test, 1 assertion) 


PHP Unitの結論は非常に簡単です。まず、PHPUnitに関するいくつかの情報と各テストの実行回数が表示されます。この場合、テストは1つだけです。 最後に、彼はテスト結果を私たちに知らせます。 BlogTestでは、1つのステートメントで1つのテストのみを実行しました。 コマンドラインでカラー出力を構成している場合、最後の行が緑色で網掛けされていることもわかります。 testSlugify()メソッドを更新して、テストが失敗したときに何が起こるかを見てみましょう。
 // src/Blogger/BlogBundle/Tests/Entity/BlogTest.php // .. public function testSlugify() { $blog = new Blog(); $this->assertEquals('hello-world', $blog->slugify('Hello World')); $this->assertEquals('a day with symfony2', $blog->slugify('A Day With Symfony2')); } 


前と同様に単体テストを再開します。 表示されます
次の
 PHPUnit 5.4.6 by Sebastian Bergmann and contributors. F 1 / 1 (100%) Time: 340 ms, Memory: 13.25MB There was 1 failure: 1) Blogger\BlogBundle\Tests\Entity\BlogTest::testSlugify Failed asserting that two strings are equal. --- Expected +++ Actual @@ @@ -'a day with symfony2' +'a-day-with-symfony2' D:\local\symfony-blog\src\Blogger\BlogBundle\Tests\Entity\BlogTest.php:15 FAILURES! Tests: 1, Assertions: 2, Failures: 1. 



今回の結論はもう少しです。 F記号は、テストが失敗したことを示しています。 テストにエラーが含まれている場合は、 Eも表示されます。 さらに、PHPユニットが障害の詳細(この場合は1)を通知します。 メソッドBlogger \ BlogBu​​ndle \ Tests \ Entity \ BlogTest :: testSlugifyは、期待値と実際の値が異なるため失敗したことがわかります。 コマンドラインにカラー出力がある場合、最後の行が赤で網掛けされていることもわかります。これは、テストにエラーがあることを示しています。 testSlugify()メソッドを修正して、成功するようにします。

 // src/Blogger/BlogBundle/Tests/Entity/BlogTest.php // .. public function testSlugify() { $blog = new Blog(); $this->assertEquals('hello-world', $blog->slugify('Hello World')); $this->assertEquals('a-day-with-symfony2', $blog->slugify('A Day With Symfony2')); } 


先に進む前に、さらにいくつかのテストを追加します。
slugify()メソッドの
 // src/Blogger/BlogBundle/Tests/Entity/BlogTest.php // .. public function testSlugify() { $blog = new Blog(); $this->assertEquals('hello-world', $blog->slugify('Hello World')); $this->assertEquals('a-day-with-symfony2', $blog->slugify('A Day With Symfony2')); $this->assertEquals('hello-world', $blog->slugify('Hello world')); $this->assertEquals('symblog', $blog->slugify('symblog ')); $this->assertEquals('symblog', $blog->slugify(' symblog')); } 



slugifyメソッドをテストしたので、Blog $タイトルが更新されたときにBlog $ slugが正しくインストールされていることを確認する必要があります。 次のメソッドをファイルに追加します
src / Blogger / BlogBu​​ndle / Tests / Entity / BlogTest.php
 // src/Blogger/BlogBundle/Tests/Entity/BlogTest.php // .. public function testSetSlug() { $blog = new Blog(); $blog->setSlug('Symfony2 Blog'); $this->assertEquals('symfony2-blog', $blog->getSlug()); } public function testSetTitle() { $blog = new Blog(); $blog->setTitle('Hello World'); $this->assertEquals('hello-world', $blog->getSlug()); } 



setSlugメソッドをテストして、更新時に$ slug要素がスラッグを正しく追加することを確認することから始めました。 次に、setTitleメソッドがBlogエンティティによって呼び出されると、$ slugが正しく更新されることを確認します。
テストを実行して、ブログエンティティの状態を確認します。

Twig拡張のテスト


前のパートでは、 \ DateTimeを文字列に変換してコメントが投稿されてからの経過時間を決定するTwig拡張機能を作成しました。 新しいファイルを作成する
src / Blogger / BlogBu​​ndle /テスト/ Twig /拡張機能/ BloggerBlogExtensionTest.php
 <?php // src/Blogger/BlogBundle/Tests/Twig/Extensions/BloggerBlogExtensionTest.php namespace Blogger\BlogBundle\Tests\Twig\Extensions; use Blogger\BlogBundle\Twig\Extensions\BloggerBlogExtension; class BloggerBlogExtensionTest extends \PHPUnit_Framework_TestCase { public function testCreatedAgo() { $blog = new BloggerBlogExtension(); $this->assertEquals("0 seconds ago", $blog->createdAgo(new \DateTime())); $this->assertEquals("34 seconds ago", $blog->createdAgo($this->getDateTime(-34))); $this->assertEquals("1 minute ago", $blog->createdAgo($this->getDateTime(-60))); $this->assertEquals("2 minutes ago", $blog->createdAgo($this->getDateTime(-120))); $this->assertEquals("1 hour ago", $blog->createdAgo($this->getDateTime(-3600))); $this->assertEquals("1 hour ago", $blog->createdAgo($this->getDateTime(-3601))); $this->assertEquals("2 hours ago", $blog->createdAgo($this->getDateTime(-7200))); // Cannot create time in the future $this->setExpectedException('\InvalidArgumentException'); $blog->createdAgo($this->getDateTime(60)); } protected function getDateTime($delta) { return new \DateTime(date("Ymd H:i:s", time()+$delta)); } } 



クラスは以前のように構成され、testCreatedAgo()メソッドを作成してTwig拡張をテストします。 このsetExpectedException()テストで別のPHPUnitメソッドを導入しました。 Twig拡張のcreatedAgoメソッドは将来の日付を処理できず、\ Exceptionに渡されることがわかっています。 getDateTime()メソッドは、\ DateTimeのインスタンスを作成する補助です。 テストプレフィックスがないため、PHPユニットはテストとしてそれを実行しようとしません。 コンソールを開き、このファイルのテストを実行します。 以前のようにテストを実行することもできますが、特定のフォルダー(およびサブフォルダー)またはファイルに対してのみテストを実行するようにPHPUnitに指示することもできます。 次のコマンドを入力します。

 $ phpunit -c app src/Blogger/BlogBundle/Tests/Twig/Extensions/BloggerBlogExtensionTest.php 


これにより、BloggerBlogExtensionTestファイルのテストのみが実行されます。 PHPUnitは、テストが失敗したことを通知します。 結論を以下に示します。
 1) Blogger\BlogBundle\Tests\Twig\Extensions\BloggerBlogExtensionTest::testCreatedAgo Failed asserting that two strings are equal. --- Expected +++ Actual @@ @@ -'0 seconds ago' +'0 second ago' //.. 


最初のステートメントは0秒前に返されると予想していましたが、2番目の単語が複数形ではなかったため返されませんでした。 Twig拡張機能を更新して修正してみましょう。
src / Blogger / BlogBu​​ndle / Twig /拡張機能/ BloggerBlogBu​​ndle.php
 <?php // src/Blogger/BlogBundle/Twig/Extensions/BloggerBlogBundle.php namespace Blogger\BlogBundle\Twig\Extensions; class BloggerBlogExtension extends \Twig_Extension { // .. public function createdAgo(\DateTime $dateTime) { // .. if ($delta < 60) { // Seconds $time = $delta; $duration = $time . " second" . (($time === 0 || $time > 1) ? "s" : "") . " ago"; } // .. } // .. } 



単体テストを再起動します。 最初のステートメントは正しく表示されますが、テストは失敗します。 次の結論を見てみましょう。

 1) Blogger\BlogBundle\Tests\Twig\Extensions\BloggerBlogExtensionTest::testCreatedAgo Failed asserting that two strings are equal. --- Expected +++ Actual @@ @@ -'1 hour ago' +'60 minutes ago' 


5番目のステートメントが失敗することがわかります。 テストを見ると、Twig拡張が適切に機能していないことがわかります。 1時間前に返されるはずでしたが、代わりに60分前に返されました。 BloggerBlogExtension Twigのコードを見ると、その理由がわかります。 オンにできる時間を比較します。つまり、 <の代わりに< =を使用します。 Twig拡張機能を更新して修正する
src / Blogger / BlogBu​​ndle / Twig /拡張機能/ BloggerBlogBu​​ndle.php
 <?php // src/Blogger/BlogBundle/Twig/Extensions/BloggerBlogBundle.php namespace Blogger\BlogBundle\Twig\Extensions; class BloggerBlogExtension extends \Twig_Extension { // .. public function createdAgo(\DateTime $dateTime) { // .. else if ($delta < 3600) { // Mins $time = floor($delta / 60); $duration = $time . " minute" . (($time > 1) ? "s" : "") . " ago"; } else if ($delta < 86400) { // Hours $time = floor($delta / 3600); $duration = $time . " hour" . (($time > 1) ? "s" : "") . " ago"; } // .. } // .. } 



次のコマンドを使用して、すべてのテストを再度実行します。

 $ phpunit -c app 


これにより、すべてのテストが実行され、すべてのテストが成功したことが示されます。 少数の単体テストのみを記述しましたが、コードを記述するときのテストがどれほど強力で重要なものであるかを理解してください。 テストは、以前の機能を損なうことなく、プロジェクトに将来の機能を追加するのにも役立ちます。 これで、単体テストのレビューを終了します。

ヒント

独自の単体テストを追加してみてください。


機能テスト


ユニットテストをいくつか作成しました。次に、いくつかのコンポーネントを一緒にテストします。 機能テストの最初のセクションには、生成された応答をテストするためのブラウザー要求のシミュレーションが含まれます。

Aboutページのテスト

まず、AboutページのPageControllerクラスをテストします。 ページは非常にシンプルなので、ここから始めるのが良いでしょう。 新しいファイルを作成する
src / Blogger / BlogBu​​ndle / Tests / Controller / PageControllerTest.php
 <?php // src/Blogger/BlogBundle/Tests/Controller/PageControllerTest.php namespace Blogger\BlogBundle\Tests\Controller; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class PageControllerTest extends WebTestCase { public function testAbout() { $client = static::createClient(); $crawler = $client->request('GET', '/about'); $this->assertEquals(1, $crawler->filter('h1:contains("About symblog")')->count()); } } 



コントローラのテストはDefaultControllerTestクラスに非常に似ていることがわかります。 aboutページをテストして、生成されたHTML内、つまりH1タグ内にあるAbout symblog行を確認します。 PageControllerTestクラスは、ユニットテストの例で見たように、\ PHPUnit_Framework_TestCaseを拡張しませんが、代わりにWebTestCaseクラスを拡張します。 このクラスはSymfony2 FrameworkBundleの一部です。

上記で説明したように、PHPUnitテストクラスは\ PHPUnit_Framework_TestCaseを拡張する必要がありますが、いくつかのテストで追加または一般的な機能が必要な場合は、独自のクラスにカプセル化してテストクラスを拡張すると便利です。 WebTestCaseはまさにそれを行い、Symfony2で機能テストを実行するためのいくつかの便利なメソッドを提供します。 vendor / symfony / symfony / src / Symfony / Bundle / FrameworkBundle / Test / WebTestCase.phpにあるWebTestCaseファイルを見ると、このクラスが実際にはKernelTestCaseクラスの拡張であることがわかります。

 // vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php abstract class WebTestCase extends KernelTestCase { // .. } 


WebTestCaseクラスのcreateClient()メソッドを見ると、Symfony2カーネルのインスタンスが作成されていることがわかります。 さらにメソッドを実行すると、(createClient()引数の1つとしてオーバーライドされない限り)環境がテストに設定されていることにも気付くでしょう。 これは、前のパートで説明したテスト環境です。

テストクラスを見ると、テストを取得して実行するためにcreateClient()メソッドが呼び出されていることがわかります。 次に、クライアント側でrequest()メソッドを呼び出して、ブラウザのURL / aboutでGET HTTPリクエストをシミュレートします(ブラウザでhttp:// localhost:8000 / aboutページにアクセスした場合もまったく同じです)。 要求は、応答を含むCrawlerオブジェクトを提供します。 Crawlerクラスは、返されたHTMLを移動できるため、非常に便利です。 Crawlerインスタンスを使用して、HTML応答のH1タグにAbout symblogという単語が含まれていることを確認します。 WebTestCaseクラスを拡張しても、以前と同じようにAssertメソッドを使用します(PageControllerTestクラスは\ PHPUnit_Framework_TestCaseクラスの子孫であることに注意してください)。

次のコマンドでPageControllerTestを実行しましょう。 テストを作成するときは、現在作業しているファイルに対してのみテストを実行するために使用すると便利です。

 $ phpunit -c app/ src/Blogger/BlogBundle/Tests/Controller/PageControllerTest.php 


メッセージOK(1つのテスト、1つのアサーション)が表示され、1つのステートメント(assertEquals())を含む1つのテスト(testAbout()が起動されたこと)がわかります。

About symblog行をContactに変更してから、テストを再度実行してください。 Contactが見つからず、assertEqualsがfalseになるため、テストは失敗します。
続行する前に、symblogについての行を戻します。
Crawlerインスタンスを使用すると、HTMLまたはXMLドキュメントを表示できます(つまり、CrawlerはHTMLまたはXMLを返す応答でのみ機能します)。 Crawlerを使用して、filter()、first()、last()、parent()などのメソッドを使用して、生成された応答を走査できます。 以前にjQueryを使用したことがある場合は、Crawlerクラスに慣れる必要があります。 サポートされているクローラーの回避策の完全なリストについては、Symfony2のテストの章を参照してください。

ホームページ


[About]ページのテストは簡単でしたが、サイトページの機能テストの基本原則を概説しました。

顧客の創造

ページリクエスト

応答チェック

これはプロセスの簡単な概要であり、実際には、リンクをクリックする、フォームに記入して送信するなど、他の多くの手順を実行できます。
ホームページをテストするメソッドを作成しましょう。 メインページにはroute /経由でアクセスでき、最新のブログエントリを表示する必要があることがわかっています。 新しいtestIndex()メソッドをPageControllerTestクラスに追加します
src / Blogger / BlogBu​​ndle / Tests / Controller / PageControllerTest.php
 // src/Blogger/BlogBundle/Tests/Controller/PageControllerTest.php public function testIndex() { $client = static::createClient(); $crawler = $client->request('GET', '/'); // Check there are some blog entries on the page $this->assertTrue($crawler->filter('article.blog')->count() > 0); } 



aboutページのテストと同じ手順を見ることができます。 テストを実行して、すべてが正しく機能していることを確認します。

 $ phpunit -c app/ src/Blogger/BlogBundle/Tests/Controller/PageControllerTest.php 


もう少し先に進みましょう。 機能テストの一部には、ユーザーがサイトで行うことを繰り返す機能が含まれます。 サイトのページをナビゲートするには、ユーザーがリンクをクリックします。 このアクションをシミュレートして、タイトルがクリックされたときに記録ページへのリンクの正確性を確認しましょう。
PageControllerTestクラスのtestIndex()メソッドを更新する
// src / Blogger / BlogBu​​ndle / Tests / Controller / PageControllerTest.php

パブリック関数testIndex()
{
// ...

//最初のリンクを見つけてタイトルを取得し、これが次のページにロードされていることを確認します
$ blogLink = $ crawler-> filter( 'article.blog h2 a')-> first();
$ blogTitle = $ blogLink-> text();
$ crawler = $ client-> click($ blogLink-> link());

// h2にブログタイトルが含まれていることを確認します
$ this-> assertEquals(1、$ crawler-> filter( 'h2:contains( "'。$ blogTitle。 '")')-> count());
}


最初に行うことは、クローラーを使用して、投稿タイトルの最初のリンクからテキストを抽出することです。 これは、 article.blog h2 a filterを使用して行われます。 このフィルターは、 article.blog記事のH2タグ内のタグを返すために使用されます。 これをよりよく理解するには、エントリーを表示するためにホームページで使用されるマークアップを見てください。
 <article class="blog"> <div class="date"><time datetime="2016-06-17T14:23:55+03:00">Friday, June 17, 2016</time></div> <header> <h2><a href="/1/a-day-with-symfony2">A day with Symfony2</a></h2> </header> //.. </article> 


article.blog h2の構造は、ホームページのレイアウトのフィルターで確認できます。 また、マークアップに一部があることにも気付くでしょう。つまり、クローラーフィルターはコレクションを返します。 最初のリンクのみが必要なので、コレクションの最初の()メソッドを使用します。 click()メソッドはリンクオブジェクトを受け取り、Crawlerインスタンスで応答を返します。 Crawlerオブジェクトが機能テストの重要な要素であることに気付くでしょう。
これで、Crawlerオブジェクトにブログページの応答が含まれます。 リンクが目的のページにリダイレクトされることをテストする必要があります。 前に抽出した$ blogTitle値を使用して、応答のタイトルを確認できます。
テストを実行して、ホームページと投稿ページ間のナビゲーションが正しく機能することを確認します。

 $ phpunit -c app/ src/Blogger/BlogBundle/Tests/Controller/PageControllerTest.php 


機能テスト中にサイトのページをナビゲートする方法を理解したので、フォームのテストに移りましょう。

連絡先ページのテスト


Symblogユーザーは、連絡先ページhttp:// localhost:8000 / contactのフォームに記入して、連絡先リクエストを送信できます。クエリが正しく機能することをテストしてみましょう。最初に、フォームが正常に送信されたときに何が起こるかを決定する必要があります(この場合、正常に送信されるとは、エラーのないフォームを意味します)。

連絡先ページに移動します。

フォームにデータを入力します。フォームを

送信します。

レターが送信されたことを

確認します。送信が成功したことを確認し


ます。

配置されたPageControllerTestクラスに新しいtestContact()メソッドを追加します
src / Blogger / BlogBu​​ndle / Tests / Controller / PageControllerTest.php
 // src/Blogger/BlogBundle/Tests/Controller/PageControllerTest.php public function testContact() { $client = static::createClient(); $crawler = $client->request('GET', '/contact'); $this->assertEquals(1, $crawler->filter('h1:contains("Contact symblog")')->count()); // Select based on button value, or id or name for buttons $form = $crawler->selectButton('Submit')->form(); $form['contact[name]'] = 'name'; $form['contact[email]'] = 'email@email.com'; $form['contact[subject]'] = 'Subject'; $form['contact[body]'] = 'The comment body must be at least 50 characters long as there is a validation constrain on the Enquiry entity'; $crawler = $client->submit($form); $this->assertEquals(1, $crawler->filter('.blogger-notice:contains("Your contact enquiry was successfully sent. Thank you!")')->count()); } 



url / contactリクエストで開始し、ページに正しいH1ヘッダーが含まれていることを確認します。次に、クローラーを使用して送信ボタンを選択します。フォームではなくボタンを選択する理由は、フォームに複数のボタンが含まれている場合があり、それらを互いに独立してクリックする場合があるためです。選択したボタンからフォームを取得できます。[]配列を使用してフォームの値を設定できます。最後に、フォームはクライアントのsubmit()メソッドに送信され、フォームを送信します。いつものように、Crawlerインスタンスを取得します。クローラーの応答を使用して、返された応答にフラッシュメッセージが存在することを確認します。テストを実行して、すべてが正常に機能していることを確認します。

 $ phpunit -c app/ src/Blogger/BlogBundle/Tests/Controller/PageControllerTest.php 


テストは失敗しました。 次のPHPUnitメッセージを受け取ります

 1) Blogger\BlogBundle\Tests\Controller\PageControllerTest::testContact Failed asserting that 0 matches expected 1. D:\local\symfony-blog\src\Blogger\BlogBundle\Tests\Controller\PageControllerTest.php:55 FAILURES! Tests: 3, Assertions: 5, Failures: 1. 


結論は、フォームが送信された後の応答でフラッシュメッセージが見つからないことを示しています。これは、テスト環境にいるときにリダイレクトが実行されないために発生しました。 PageControllerクラスでフォームが正常に検証されると、リダイレクトが発生します。このリダイレクトは発生しません。尊重する必要があることを明示的に示す必要があります。リダイレクトが実行されない理由は、現在の応答を最初に確認する必要がある可能性があるため、単純です。これは、後でメッセージが送信されたかどうかを確認するときに表示されます。 PageControllerTestクラスを更新して、リダイレクトを設定します。

 // src/Blogger/BlogBundle/Tests/Controller/PageControllerTest.php public function testContact() { // .. $crawler = $client->submit($form); // Need to follow redirect $crawler = $client->followRedirect(); $this->assertEquals(1, $crawler->filter('.blogger-notice:contains("Your contact enquiry was successfully sent. Thank you!")')->count()); } 


ここで、PHPUnitテストを実行する場合、それらに合格する必要があります。次に、連絡先フォームの送信プロセスをチェックする最終段階、ステップ4、メールが送信されたことを確認します。次の構成が原因で、テスト環境でメールが配信されないことがすでにわかっています。

 # app/config/config_test.yml swiftmailer: disable_delivery: true 


Webプロファイラーを通じて収集された情報を使用して、電子メールが送信されたことを確認できます。ここで、クライアントをリダイレクトしないことが重要です。プロファイラーの検証は、リダイレクトが発生する前に行う必要があります。そうしないと、プロファイラー内の情報が失われます。
testContact()メソッドを更新する
 // src/Blogger/BlogBundle/Tests/Controller/PageControllerTest.php public function testContact() { // .. $crawler = $client->submit($form); // Check email has been sent if ($profile = $client->getProfile()) { $swiftMailerProfiler = $profile->getCollector('swiftmailer'); // Only 1 message should have been sent $this->assertEquals(1, $swiftMailerProfiler->getMessageCount()); // Get the first message $messages = $swiftMailerProfiler->getMessages(); $message = array_shift($messages); $symblogEmail = $client->getContainer()->getParameter('blogger_blog.emails.contact_email'); // Check message is being sent to correct address $this->assertArrayHasKey($symblogEmail, $message->getTo()); } // Need to follow redirect $crawler = $client->followRedirect(); $this->assertTrue($crawler->filter('.blogger-notice:contains("Your contact enquiry was successfully sent. Thank you!")')->count() > 0); } 



フォームを送信した後、現在の環境の構成を使用してプロファイラーを無効にできるため、プロファイラーが使用可能かどうかを確認します。

ヒント

テストはテスト環境で実行するのではなく、プロファイラーなどが利用できない本番環境で実行する必要があることに注意してください。


プロファイラーを取得できる場合は、swiftmailerコレクターを取得するリクエストを作成します。swiftmailerコレクターは舞台裏で働き、電子メールサービスの使用方法に関する情報を収集します。これを使用して、送信された手紙に関する情報を取得できます。
次に、getMessageCount()メソッドを使用して、1つの電子メールが送信されたことを確認します。これは、メールが送信されたことを確認するには十分ですが、メールが適切な場所に送信されることを確認しません。
ここでテストを再開し、すべてが正常に機能していることを確認します。

 $ phpunit -c app/ src/Blogger/BlogBundle/Tests/Controller/PageControllerTest.php 


追加コメントのテスト

次に、連絡先情報ページの以前のテストで得られた知識を使用して、投稿にコメントを追加するプロセスをテストしましょう。繰り返しますが、フォームが正常に送信されたときに何が起こるべきかを概説します。

ページの記録への移行

するためのフォームを記入

フォーム送信

コメントすべてのコメントの最後に追加されたことを確認し

、最新のコメント(コメントリストの最初のものを)チェックし、サイドバーのブロックを


中に新しいファイルを作成します。
src / Blogger / BlogBu​​ndle / Tests / Controller / BlogControllerTest.php
 <?php // src/Blogger/BlogBundle/Tests/Controller/BlogControllerTest.php namespace Blogger\BlogBundle\Tests\Controller; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class BlogControllerTest extends WebTestCase { public function testAddBlogComment() { $client = static::createClient(); $crawler = $client->request('GET', '/1/a-day-with-symfony'); $this->assertEquals(1, $crawler->filter('h2:contains("A day with Symfony2")')->count()); // Select based on button value, or id or name for buttons $form = $crawler->selectButton('Submit')->form(); $crawler = $client->submit($form, array( 'blogger_blogbundle_commenttype[user]' => 'name', 'blogger_blogbundle_commenttype[comment]' => 'comment', )); // Need to follow redirect $crawler = $client->followRedirect(); // Check comment is now displaying on page, as the last entry. This ensure comments // are posted in order of oldest to newest $articleCrawler = $crawler->filter('section .previous-comments article')->last(); $this->assertEquals('name', $articleCrawler->filter('header span.highlight')->text()); $this->assertEquals('comment', $articleCrawler->filter('p')->last()->text()); // Check the sidebar to ensure latest comments are display and there is 10 of them $this->assertEquals(10, $crawler->filter('aside.sidebar section')->last() ->filter('article')->count() ); $this->assertEquals('name', $crawler->filter('aside.sidebar section')->last() ->filter('article')->first() ->filter('header span.highlight')->text() ); } } 



コードの調査を開始する前に、このファイルのテストを実行して、すべてが正常に機能していることを確認します。
 $ phpunit -c app/ src/Blogger/BlogBundle/Tests/Controller/BlogControllerTest.php 


PHPUnitは、1つのテストが成功したことを通知する必要があります。testAddBlogComment()のコードを見ると、クライアントの作成、ページのリクエスト、およびその検証を確認できます。次に、コメントの追加フォームを受信し、フォームを送信します。フォームの値を入力する方法は、以前のバージョンとは少し異なります。今回はsubmit()メソッドの2番目のクライアント引数を使用してフォーム値を追加します。

ヒント

オブジェクト指向のインターフェイスを使用して、フォームフィールドの値を設定することもできます。以下に例を示します。

 // Tick a checkbox $form['show_emal']->tick(); // Select an option or a radio $form['gender']->select('Male'); 



フォームを送信した後、応答を確認できるようにリダイレクトに従う必要があるクライアントをリクエストします。クローラーを再び使用して、最新のブログコメントを取得します。最後に、サイドバーの最新のコメントをチェックして、コメントがリストの最初であることを確認します。

ブログリポジトリ

機能テストの最後の部分では、Doctrine 2リポジトリのテストを調べます。新しいファイルを作成する
src / Blogger / BlogBu​​ndle /テスト/リポジトリ/ BlogRepositoryTest.php
 <?php // src/Blogger/BlogBundle/Tests/Repository/BlogRepositoryTest.php namespace Blogger\BlogBundle\Tests\Repository; use Blogger\BlogBundle\Entity\Repository\BlogRepository; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class BlogRepositoryTest extends WebTestCase { /** * @var \Blogger\BlogBundle\Entity\Repository\BlogRepository */ private $blogRepository; public function setUp() { $kernel = static::createKernel(); $kernel->boot(); $this->blogRepository = $kernel->getContainer() ->get('doctrine.orm.entity_manager') ->getRepository('BloggerBlogBundle:Blog'); } public function testGetTags() { $tags = $this->blogRepository->getTags(); $this->assertTrue(count($tags) > 1); $this->assertContains('symblog', $tags); } public function testGetTagWeights() { $tagsWeight = $this->blogRepository->getTagWeights( array('php', 'code', 'code', 'symblog', 'blog') ); $this->assertTrue(count($tagsWeight) > 1); // Test case where count is over max weight of 5 $tagsWeight = $this->blogRepository->getTagWeights( array_fill(0, 10, 'php') ); $this->assertTrue(count($tagsWeight) >= 1); // Test case with multiple counts over max weight of 5 $tagsWeight = $this->blogRepository->getTagWeights( array_merge(array_fill(0, 10, 'php'), array_fill(0, 2, 'html'), array_fill(0, 6, 'js')) ); $this->assertEquals(5, $tagsWeight['php']); $this->assertEquals(3, $tagsWeight['js']); $this->assertEquals(1, $tagsWeight['html']); // Test empty case $tagsWeight = $this->blogRepository->getTagWeights(array()); $this->assertEmpty($tagsWeight); } } 


データベースへの正しい接続を必要とするテストを実行したいので、Symfony2 Kernelをダウンロードできるため、WebTestCaseを再度拡張します。次のコマンドでこのファイルのテストを実行します。

 $ phpunit -c app/ src/Blogger/BlogBundle/Tests/Repository/BlogRepositoryTest.php 


コードカバレッジ

コードカバレッジにより、テストの実行時にコードのどの部分が実行されるかがわかります。これにより、テストでカバーされていないコード部分を確認し、それらのテストを作成するかどうかを決定できます。

アプリケーションのコードカバレッジを表示するには、コンソールに入力します

 $ phpunit --coverage-html ./phpunit-report -c app/ 


コマンドが機能することを覚えておいてください、phpでxdebug有効にする必要があります
これにより、プロジェクトルートのphpunit-reportフォルダーコードカバレッジ分析が出力されますブラウザーでこのフォルダーからindex.htmlファイル開き、分析結果を確認します。



おわりに



テストでは、いくつかの重要な領域を調査しました。ユニットテストと機能テストの両方を調べて、サイトが適切に機能していることを確認しました。ブラウザのリクエストをシミュレートする方法と、Symfony2 Crawlerクラスを使用してこれらのリクエストのレスポンスを検証する方法を見ました。

ソースとサポート資料:

https : //symfony.com/
http://tutorial.symblog.co.uk/
https://phpunit.de/

ポスト台本
プロジェクトに寄せられた注意とコメントに感謝します。問題や質問がある場合は、コメントやプライベートメッセージの購読を解除し、友達として追加してください。


パート1-Symfony2とテンプレートの構成
パート2-連絡先ページ:バリデーター、フォーム、およびメール
パート3-Doctrine 2とデータフィクスチャ
パート4-Doctrine 2のコメントモデル、リポジトリ、移行
パート5-Twig拡張、サイドバー、および資産


また、マニュアルが気に入ったら、プロジェクトリポジトリにスターを付けるか、購読することができますありがとう

Source: https://habr.com/ru/post/J303578/


All Articles