読者です 読者をやめる 読者になる 読者になる

ITの隊長のブログ

ITの隊長のブログです。いや、まだ隊長と呼べるほどには至っていないけど、日々がんばります。CakePHPとPlayFrameworkを使って仕事しています。最近はAngular2をさわりはじめたお(^ω^ = ^ω^)

CakePHPで継続的インテグレーションその2

CakePHP PHP User story

スポンサードリンク

photo by garrettc

さて、第2回。

前回

aipacommander.hatenablog.jp

今回はユーザーストーリーのお話。

ユーザーストーリー

◯◯として、××できる、なぜなら△△▽▽したい(する)からだ

とまぁ、こういう箇条書きでアプリケーションの特徴を書き出すことを「ユーザーストーリー」と呼ぶらしい。

んで、今回はBDDで開発していくっとよ。

  1. ユーザーストーリーを定義
  2. 設計後、実装可能な単位に分割する
  3. 機能を実装 -> ユニットテストが成功する
  4. ユーザーストーリーのテストが成功する

図がありますが、ずっとグルグルする図になっています。

f:id:aipacommander:20150915114402p:plain

(なんかAmazonの図を思い出しました)

f:id:aipacommander:20150915114445j:plain

いまいちアジャイルのことがよくわかっていませんが、とりあえず進めることにします。

ユーザーストーリーの定義

本を読む。うんうん。なるほどね。(よくわからないワードがいっぱいでてきたぞー!!!!ヤベェ!)

とりあえず、箇条書きにまとめていく。

  1. BDDを使うお(^ω^
  2. BDDを使うにはDSLドメイン特化言語)を使うお(^ω^;
  3. DSLには「Gherkin(ガーキン)」とか「Cucumber(キューカンバー。。。きゅうり?)」、「Behat(?)」を使って自動実行していくお(°ω°;

ちょっと泣きそうです。なんか難しくない?

試してみる

機能や記法の説明から入っていますが、よくわかりませんので、とりあえず先に動かしてみます。

BDDプラグインのインストール

composerを使ってインストール

$ cat composer.json
{
    "name": "php_ci_book/blogapp",
    "authors": [
        {
            "name": "test",
            "email": "test@gmail.com"
        }
    ],
    "config": {
        "vendor-dir":"Vendor"
    },
    // ここから
    "repositories": [
        {
            "type": "vcs",
            "url" : "git://github.com/sizuhiko/Bdd.git"
        }
    ],
    // ここまでを追加
    "require": {
        "cakephp/cakephp": "2.6.*"
    },
    // ここから
    "require-dev": {
        "pear/console_commandline": "@dev",
        "pear/pear_exception": "@dev",
        "sizuhiko/Bdd": "dev-master"
    }
    // ここまでも追加
}
$ composer require --dev sizuhiko/Bdd:dev-master
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)           
  - Installing composer/installers (v1.0.21)
    Loading from cache

  - Installing symfony/yaml (v2.7.4)
    Downloading: 100%         

  - Installing symfony/translation (v2.7.4)
    Downloading: 100%         

  - Installing symfony/event-dispatcher (v2.7.4)
    Downloading: 100%         

  - Installing symfony/dependency-injection (v2.7.4)
    Downloading: 100%         

  - Installing symfony/filesystem (v2.7.4)
    Downloading: 100%         

  - Installing symfony/config (v2.7.4)
    Downloading: 100%         

  - Installing symfony/console (v2.7.4)
    Downloading: 100%         

  - Installing symfony/finder (v2.7.4)
    Downloading: 100%         

  - Installing behat/gherkin (v2.3.5)
    Downloading: 100%         

  - Installing behat/behat (v2.5.5)
    Downloading: 100%         

  - Installing behat/common-contexts (v1.2.0)
    Downloading: 100%         

  - Installing phpunit/php-text-template (1.2.1)
    Loading from cache

  - Installing phpunit/phpunit-mock-objects (1.2.3)
    Loading from cache

  - Installing phpunit/php-timer (1.0.7)
    Loading from cache

  - Installing phpunit/php-file-iterator (1.4.1)
    Loading from cache

  - Installing phpunit/php-token-stream (1.2.2)
    Loading from cache

  - Installing phpunit/php-code-coverage (1.2.18)
    Loading from cache

  - Installing phpunit/phpunit (3.7.38)
    Loading from cache

  - Installing hamcrest/hamcrest-php (v1.1.1)
    Downloading: 100%         

  - Installing pear/pear_exception (dev-master 8c18719)
    Cloning 8c18719fdae000b690e3912be401c76e406dd13b

  - Installing pear/console_commandline (dev-trunk 18ac06e)
    Cloning 18ac06ef5d0ea4db3522b1d0b5869547f0aac933

  - Installing sizuhiko/spec-php (0.9.6.2)
    Downloading: 100%         

  - Installing symfony/css-selector (v2.7.4)
    Downloading: 100%         

  - Installing behat/mink (v1.5.0)
    Downloading: 100%         

  - Installing behat/mink-extension (v1.2.0)
    Downloading: 100%         

  - Installing sizuhiko/bdd (dev-master 58e4431)
    Cloning 58e44318a62fbd0a79d7cf6cbea1e7fcc4877871
# ~ 省略 ~
Writing lock file
Generating autoload files

すげー色々落ちてきた。

Package guzzle/common is abandoned, you should avoid using it. Use guzzle/guzzle instead.
Package guzzle/stream is abandoned, you should avoid using it. Use guzzle/guzzle instead.
Package guzzle/parser is abandoned, you should avoid using it. Use guzzle/guzzle instead.
Package guzzle/http is abandoned, you should avoid using it. Use guzzle/guzzle instead.

このエラーはよくわからん。のでぐぐったら、どうやらライブラリが足りないらしい。。。(多分)

なので、こいつもインストール

$ composer require guzzle/guzzle:~3.9

あと、ついでにこのプラグインもインストールしておいてね。だって。

$ composer require --dev behat/mink-goutte-driver:*

ロード設定

  • ~/Config/bootstrap/environments/development.php
<?php
Environment::configure('development', true, [
   'MYSQL_DB_HOST'      => 'localhost',
   'MYSQL_USERNAME'     => 'xxx',
   'MYSQL_PASSWORD'     => 'xxx',
   'MYSQL_DB_NAME'      => 'db_name',
   'MYSQL_TEST_DB_NAME' => 'test_db_name',
   'MYSQL_PREFIX'       => ''
// ここから追記
], function() {
    CakePlugin::load('Bdd');
});

こんな書き方もできるのね。(普通か)

んで、プラグインの初期構築のためcakeを実行する

$ ./Console/cake Bdd.init

behat.ymlが自動生成されます。ファイルを修正します。

default:
  paths:
    features: ../../features
  extensions:
    Behat\MinkExtension\Extension:
      base_url:  'http://test.localhost:8888/application-name/' # ここを修正します。
      goutte:
        guzzle_parameters:
          request.params:
            redirect.disable: true
      # 
      # switch disable followings if use behat/mink-selenium2-driver 
      #
      # selenium: ~ # ここはコメントアウト
      # javascript_session: selenium # ここも
      # 
      # switch enable followings if use behat/mink-selenium2-driver 
      #
      # javascript_session: selenium2
      # browser_name: 'firefox'
      # selenium2:                    
      #   capabilities: { "browser": "firefox"}

おお!seleniumも使えるのね。

最後に追加したプラグインをコミットします。

プラグインを実行してみる

実行してみます。

と、ここで事件が

$ ./Console/cake Bdd.story --help

Welcome to CakePHP v2.6.11 Console
---------------------------------------------------------------
App : cakephp_integlation
Path: /Users/git/cakephp_integlation/
---------------------------------------------------------------
/Users/git/cakephp_integlation/Plugin/BddPHP Fatal error:  Class 'Behat\Behat\Console\BehatApplication' not found in /Users/git/cakephp_integlation/Plugin/Bdd/Console/Command/StoryShell.php on line 28

Fatal error: Class 'Behat\Behat\Console\BehatApplication' not found in /Users/git/cakephp_integlation/Plugin/Bdd/Console/Command/StoryShell.php on line 28
Fatal Error Error: Class 'Behat\Behat\Console\BehatApplication' not found in [/Users/git/cakephp_integlation/Plugin/Bdd/Console/Command/StoryShell.php, line 28]

・・・・???

どうやら、autoload.phpのパスが違うらしい

2つのファイルの1~10行目あたりにある、autoload.phpの読み込み箇所を変更する

  • ~/Plugin/Bdd/Console/Command/SpecShell.php
<?php
// ~ 省略 ~
if(file_exists(dirname(dirname(dirname(__FILE__))).DS.'..'.DS.'..'.DS.'vendor/autoload.php')) {
    require dirname(dirname(dirname(__FILE__))).DS.'..'.DS.'..'.DS.'vendor/autoload.php';
}
  • ~/Plugin/Bdd/Console/Command/StoryShell.php
<?php
// ~ 省略 ~
if(file_exists(dirname(dirname(dirname(__FILE__))).DS.'..'.DS.'..'.DS.'vendor/autoload.php')) {
    require dirname(dirname(dirname(__FILE__))).DS.'..'.DS.'..'.DS.'vendor/autoload.php';
}

変更後実行すると、問題なかった。

$ ./Console/cake Bdd.story --help

Welcome to CakePHP v2.6.11 Console
---------------------------------------------------------------
App : cakephp_integlation
Path: /Users/git/cakephp_integlation/
---------------------------------------------------------------
/Users/git/cakephp_integlation/Plugin/BddUsage:
  behat [--init] [-f|--format="..."] [--out="..."] [--lang="..."] [--[no-]ansi] [--[no-]time] [--[no-]paths] [--[no-]snippets] [--[no-]snippets-paths] [--[no-]multiline] [--[no-]expand] [--story-syntax] [-d|--definitions="..."] [--name="..."] [--tags="..."] [--cache="..."] [--strict] [--dry-run] [--stop-on-failure] [--rerun="..."] [--append-snippets] [--append-to="..."] [features]

Arguments:
  features                       Feature(s) to run. Could be:
                                              - a dir (features/)

フィーチャを記述する

  • ~/Plugin/Bdd/features/blog_new_post.feature
# langage: ja
フィーチャ: 会員として新しい記事を投稿できる、なぜなら会員は自分の言葉で発信したいからだ
背景:
  前提 "会員" としてログインしている
シナリオ: 新しい記事を投稿できる
  もし 以下の内容で記事を投稿する
    | タイトル | はじめてのブログ |
    | 本文    | はじめまして     |
  ならば 新しい記事が登録されていること
シナリオ: タイトルなしでは新しい記事は投稿できない
  もし 以下の内容で記事を投稿する
    | タイトル |            |
    | 本文    | はじめまして |
  ならば 新しい記事が登録できないこと

実行。ムッ?

$ ./Console/cake Bdd.story

Welcome to CakePHP v2.6.11 Console
---------------------------------------------------------------
App : cakephp_integlation
Path: /Users/git/cakephp_integlation/
---------------------------------------------------------------
/Users/git/cakephp_integlation/Plugin/Bdd

                                                                                                                                                                                     
  [Behat\Gherkin\Exception\ParserException]                                                                                                                                          
  Expected Comment or Scenario or Outline or Step token, but got Text on line: 2 in file: /Users/git/cakephp_integlation/Plugin/Bdd/features/blog_new_post.feature  

・・・・? あ

  • ~/Plugin/Bdd/features/blog_new_post.feature
# language: ja

languageuが間違えていたようです。

修正し、再度実行

$ ./Console/cake Bdd.story

Welcome to CakePHP v2.6.11 Console
---------------------------------------------------------------
App : cakephp_integlation
Path: /Users/git/cakephp_integlation/
---------------------------------------------------------------
/Users/git/cakephp_integlation/Plugin/Bddフィーチャ: 会員として新しい記事を投稿できる、なぜなら会員は自分の言葉で発信したいからだ

  背景:                   # /Users/git/cakephp_integlation/Plugin/Bdd/features/blog_new_post.feature:3
    前提 "会員" としてログインしている

  シナリオ: 新しい記事を投稿できる     # /Users/git/cakephp_integlation/Plugin/Bdd/features/blog_new_post.feature:5
    もし 以下の内容で記事を投稿する
      | タイトル | はじめてのブログ |
      | 本文   | はじめまして   |
    ならば 新しい記事が登録されていること

  シナリオ: タイトルなしでは新しい記事は投稿できない # /Users/git/cakephp_integlation/Plugin/Bdd/features/blog_new_post.feature:10
    もし 以下の内容で記事を投稿する
      | タイトル |        |
      | 本文   | はじめまして |
    ならば 新しい記事が登録できないこと

2 個のシナリオ (2 個未定義)
6 個のステップ (6 個未定義)
0m0.045s

未定義のステップを、次のスニペットで実装できます:

$steps->Given('/^"([^"]*)" としてログインしている$/', function($world, $arg1) {
    throw new \Behat\Behat\Exception\PendingException();
});

$steps->Given('/^以下の内容で記事を投稿する$/', function($world, $table) {
    throw new \Behat\Behat\Exception\PendingException();
});

$steps->Given('/^新しい記事が登録されていること$/', function($world) {
    throw new \Behat\Behat\Exception\PendingException();
});

$steps->Given('/^新しい記事が登録できないこと$/', function($world) {
    throw new \Behat\Behat\Exception\PendingException();
});

うむむ。。。いまいちよくわからん。。。w (^^;

あともうひとつ作成します。

  • ~/Plugin/Bdd/features/blog_posts.feature
# language: ja
フィーチャ: 会員として記事を一覧表示できる、なぜなら会員はこれまでに書いた記事をまとめて確認したいからだ
背景:
  前提 "会員" としてログインしている
シナリオ: 記事を一覧表示できる
  前提   記事が9件登録されている
  もし   自分の投稿を一覧表示する
  ならば ページ 1 に投稿が新しい順で 5 件表示されている
  かつ   ページ 2 に投稿が新しい順で 4 件表示されている

これで、おk.最後に作成したファイルをコミットしましょう。

今回はここまで。

いまいち何ができるかなんてピンと来ないけど、これが役に建つんだろうね( ´_ゝ`)

ユーザーストーリーの書き方は別記事でまとめようかな。

これまでの記事

aipacommander.hatenablog.jp

参考書籍

CakePHPで学ぶ継続的インテグレーション

CakePHPで学ぶ継続的インテグレーション

CakePHPで学ぶ継続的インテグレーション (impress top gear)

CakePHPで学ぶ継続的インテグレーション (impress top gear)