search
LoginSignup
4

More than 5 years have passed since last update.

posted at

updated at

Organization

CakePHP3 のアプリケーションを Behat でテストする(update編)

CakePHP Advent Calendar 2017の9日目です(ギリ間に合った...
@o0h さんの昨日の記事は、CakePHP3のコントローラーのテストはどうするかでした。

CakePHP3でBDDをするには、 Behat を使うことでシナリオテストを記述することができます。
BehatはE2Eテストをするのに適したテスティングフレームワークで、自然言語(つまり日本語)で記述できるのが特徴です。

CakePHP2でBDDをしたい方は、私作ではありますが CakePHP2 BDDプラグインがありますので、ご利用ください。

きっかけ

実は最近BehatとかBDDとか言ってなかったのですが、このツイートが飛んできました。

うわー、2年以上もメンテしてなかったCakePHP3のBDDチュートリアルです。

そしてインターネット怖いね、CakePHP + BehatについてCakeFestで発表した動画 - 2014年まであるよ。

これ、最新版のPHPとかCakePHPでも動くのかな....

と心配になったのは言うまでもありません。

2年前の記憶

こういうBlogを日本語でも書いていました。
CakePHP3 のアプリケーションを Behat でテストする

今回は、このブログ記事で書いていた内容を、現時点のバージョンにアップグレードしてみたよ編としてお送ります。

アップデートしてみた

PHP7.1 へのアップグレード

  • Vagrant/Virtual Boxを最新版にする
  • まっさらな状態から手順を進めてみる
  • cakeboxのサイトにPHP 7.1へのアップグレード手順があったのでやってみる

さて、ここでPHP7.1 のアップグレードで失敗します。
どうもアップグレードシェルでPHP7をインストールするのにPPAリポジトリを追加するため add-apt-repository コマンドを使っているのですが、見つからないとエラーになります。

これを予めインストールするように README.mdに追記しました。

localhost:cakebox $ vagrant ssh
vagrant@cakebox $ sudo apt-get update
vagrant@cakebox $ sudo apt-get install software-properties-common python-software-properties
vagrant@cakebox $ /cakebox/bash/ubuntu-16.sh
vagrant@cakebox $ exit
localhost:cakebox $ vagrant reload

アップグレードが終わるとPHPのバージョンが7.1.12になっています。

localhost:cakebox $ vagrant ssh
vagrant@cakebox:~$ php -v
PHP 7.1.12-2+ubuntu16.04.1+deb.sury.org+2 (cli) (built: Dec  7 2017 20:12:04) ( NTS )

依存関係のアップグレード

いったん以下の手順まで進めます。

vagrant@cakebox:~/Apps/blog-tutorial.app$ composer install

これで composer.lock ファイルから2年前のバージョンがインストールされます。

composer.json をみると、そこそこ書き換わってくれそうですので、 composer update で全アップデートをかけます(update された部分だけ抜粋しています)。

vagrant@cakebox:~/Apps/blog-tutorial.app$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 24 installs, 53 updates, 6 removals
  - Updating cakephp/plugin-installer (0.0.11 => 1.0.0): Downloading (100%)         
  - Updating mobiledetect/mobiledetectlib (2.8.12 => 2.8.28): Downloading (100%)         
  - Updating psr/log (1.0.0 => 1.0.2): Downloading (100%)         
  - Updating cakephp/cakephp (3.0.1 => 3.4.1): Downloading (100%)         
  - Updating robmorgan/phinx (v0.4.3 => v0.8.1): Downloading (100%)         
  - Updating cakephp/migrations (1.1.0 => 1.7.1): Downloading (100%)         
  - Updating vlucas/phpdotenv (v1.1.0 => v1.1.1): Downloading (100%)         
  - Updating jakub-onderka/php-console-highlighter (v0.3.1 => v0.3.2): Downloading (100%)         
  - Updating nikic/php-parser (v1.2.2 => v3.1.2): Downloading (100%)         
  - Updating psy/psysh (v0.4.4 => v0.8.15): Downloading (100%)         
  - Updating cakephp/debug_kit (3.0.1 => 3.11.2): Downloading (100%)         
  - Updating cakephp/bake (1.0.4 => 1.3.7): Downloading (100%)         
  - Updating behat/mink (v1.6.1 => v1.7.1): Downloading (100%)         
  - Updating behat/transliterator (v1.0.1 => v1.2.0): Downloading (100%)         
  - Updating behat/gherkin (v4.3.0 => v4.5.1): Downloading (100%)         
  - Updating behat/behat (v3.0.15 => v3.4.3): Downloading (100%)         
  - Updating behat/mink-extension (v2.0.1 => 2.3.0): Downloading (100%)         
  - Updating guzzlehttp/guzzle (5.2.0 => 6.3.0): Downloading (100%)         
  - Updating fabpot/goutte (v2.0.3 => v3.2.2): Downloading (100%)         
  - Updating behat/mink-browserkit-driver (v1.2.0 => v1.3.2): Downloading (100%)         
  - Updating behat/mink-goutte-driver (v1.1.0 => v1.2.1): Downloading (100%)         
  - Updating sebastian/version (1.0.5 => 1.0.6): Downloading (100%)         
  - Updating sebastian/global-state (1.0.0 => 1.1.1): Downloading (100%)         
  - Updating sebastian/recursion-context (1.0.0 => 1.0.5): Downloading (100%)         
  - Updating sebastian/exporter (1.2.0 => 1.2.2): Downloading (100%)         
  - Updating sebastian/environment (1.2.2 => 1.3.8): Downloading (100%)         
  - Updating sebastian/diff (1.3.0 => 1.4.3): Downloading (100%)         
  - Updating sebastian/comparator (1.1.1 => 1.2.4): Downloading (100%)         
  - Updating phpunit/php-text-template (1.2.0 => 1.2.1): Downloading (100%)         
  - Updating doctrine/instantiator (1.0.4 => 1.1.0): Downloading (100%)         
  - Updating phpunit/phpunit-mock-objects (2.3.1 => 2.3.8): Downloading (100%)         
  - Updating phpunit/php-timer (1.0.5 => 1.0.9): Downloading (100%)         
  - Updating phpunit/php-file-iterator (1.4.0 => 1.4.5): Downloading (100%)         
  - Updating phpunit/php-token-stream (1.4.1 => 1.4.12): Downloading (100%)         
  - Updating phpunit/php-code-coverage (2.0.16 => 2.2.4): Downloading (100%)         
  - Updating phpdocumentor/reflection-docblock (2.0.4 => 4.2.0): Downloading (100%)         
  - Updating phpspec/prophecy (v1.4.1 => 1.7.3): Downloading (100%)         
  - Updating phpunit/phpunit (dev-master 13a957b => 4.8.36):  Checking out 46023de9a9
  - Updating fzaninotto/faker (v1.4.0 => v1.7.1): Downloading (100%)         
  - Updating sizuhiko/fabricate (2.0.0 => 2.0.3): Downloading (100%)         
  - Updating sizuhiko/cake_fabricate dev-master (1b445ef => ed1f8d4):  Checking out ed1f8d4751
symfony/var-dumper suggests installing ext-symfony_debug ()
Writing lock file
Generating autoload files

いろいろ新しくなりました。
あとは元の手順を進め(PHPのバージョンが変わった部分を適時置き換え)、緊張の瞬間です。

Behatのテストを実行する

vagrant@cakebox:~/Apps/blog-tutorial.app$ vendor/bin/behat
Feature:
  In order to tell the masses what's on my mind
  As a user
  I want to read articles on the site

  Background:                # features/articles.feature:7
    Given there is a post:   # ArticlesContext::thereIsAPost()
      | Title              | Body                          |
      | The title          | This is the post body.        |
      | A title once again | And the post body follows.    |
      | Title strikes back | This is really exciting! Not. |
    And there is a user:     # UsersContext::thereIsAUser()
      | Username | Password | FirstName | LastName |
      | alice    | ecila    | Alice     | Smith    |
      | bob      | obo      | Bob       | Johnson  |
    And there is a category: # CategoriesContext::thereIsACategory()
      | Name      |
      | Events    |
      | Computers |
      | Foods     |

  Scenario: Show articles                 # features/articles.feature:23
    When I am on "TopPage"                # WebContext::visit()
    Then I should see "The title"         # WebContext::assertPageContainsText()
    And I should see "A title once again" # WebContext::assertPageContainsText()
    And I should see "Title strikes back" # WebContext::assertPageContainsText()

  Scenario: Show the article                       # features/articles.feature:29
    Given I am on "TopPage"                        # WebContext::visit()
    When I follow "A title once again"             # WebContext::clickLink()
    Then I should see "And the post body follows." # WebContext::assertPageContainsText()

  Scenario: Add new article                         # features/articles.feature:34
    Given I am on "TopPage"                         # WebContext::visit()
    And I follow "Add"                              # WebContext::clickLink()
    And I login "bob" "obo"                         # UsersContext::iLogin()
    When I post article form :                      # ArticlesContext::iPostArticleForm()
      | Label      | Value                 |
      | Categories | Events                |
      | Title      | Today is Party        |
      | Body       | From 19:30 with Alice |
    And I should see "Your article has been saved." # WebContext::assertPageContainsText()
    And I should see "Today is party"               # WebContext::assertPageContainsText()

  Scenario: Remove article                     # features/articles.feature:46
    Given I am on "TopPage"                    # WebContext::visit()
    When I delete article "Title strikes back" # ArticlesContext::iDeleteArticle()
    Then I should not see "Title strikes back" # WebContext::assertPageNotContainsText()

4 scenarios (4 passed)
28 steps (28 passed)
0m12.62s (32.10Mb)

おー、全部成功しています。

何が言いたかったのか

さて、皆さんは現場で composer update なんて実行しますか?
まぁ普通はしませんよね。
私は今回やりました。もちろんサンプルアプリだし、仕事のアプリじゃないから、というのも言えるでしょう。
とはいえ、サンプルアプリでも動作確認をしないといけませんし、うまく動かなかったら...
このサンプルアプリには単体テストはありませんが、E2Eテストは存在していました(まぁE2Eのチュートリアルなので当然ですが...)。
全部アップデートしても、エンドツーエンドでちゃんと動くことがコマンド1つで確認できます。

単体テストももちろん大事ですが、E2Eテストがあるときの安心感は今回改めて感じました。

さいごに

あいかわらず単体テスト(PHPSpec)に関しては未着手なのですが、いろいろ考えてPHPUnitベースでBDDスタイルに記述できる Codeception/Specify を使うと良いのかなーと思います。これだとPHPUnitのコードと共存できるし、少しずつ書き換えたりできるな、と。

CakePHP3のBDDチュートリアルは、最新版で試せるように変更は反映されています。

明日は @ryoichi-u さんの「Phinxの話か、Formヘルパーのエスケープ周りか」が予定されています。楽しみですね。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
4