LoginSignup
6
4

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-12-09

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ヘルパーのエスケープ周りか」が予定されています。楽しみですね。

6
4
0

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
  3. You can use dark theme
What you can do with signing up
6
4