SlideShare a Scribd company logo
1 of 37
第65回 PHP勉強会
 @東京(Engine Yard)

behat/PHPUnitで始める
     BDD/TDD


2013/02/28(木)   @ビルコム
前置き。
about tchikuba
• 所属
   – ビルコム株式会社
• 自社サービス
   – ReBuy http://rebuy.jp/
   – Okkru https://okkru.jp
• 役割
   – 開発Playing Manager
• いいね!
   – Linux、ビール、宇宙平和
• facebook/twitter
   – tchikuba
ReBuy:facebookコマースアプリ
Okkru:ソーシャルギフト
我々の諸環境
•   OS:CentOS(nifty cloud)
•   Webサーバ:Nginx/Apache
•   DBサーバ:MySQL
•   CIサーバ:Jenkins/SeleniumServer
•   言語:PHP
•   フレームワーク:Zendframework
•   フロント:jQuery(Mobile)
•   SCM:Git
•   BTS:Backlog
聞きたいこと。




•開発プロセス?
•BDD/TDD?
本題。
TDDとは
• Test-Driven Developmentの

• 和訳:テスト駆動開発

• 特徴
  – テストファースト
  – リファクタリング


• メリット
  – スパゲッティの塩分低下
  – 開発アジリティ上昇
BDDとは
• Behavior-Driven Developmentの

• 和訳:振舞駆動開発

• 特徴
  – 自然言語
  – 要求仕様(スペック)


• メリット
  –  け れ 厙
  – オブジェクト指向強化
BDD/TDDのフレームワーク
  • BDD
   – behat + mink
   – PHPSpec
   – Selenium


  • TDD
   – PHPUnit
PHPUnit。
behat。
behat環境設定
• インストール (PHP5.3.4 ≧推奨)
 – Composer
   • vi composer.json
   • curl http://getcomposer.org/installer | php
   • php composer.phar install
 – PHAR
 – Git
• 初期プロジェクト生成
 – behat --init
ディレクトリ構成
• behat_root/
  – features/
     • bootstrap/
        – FeatureContext.php
     • *.feature
  – behat.yml
  – build.xml *for Jenkins

• *.feature:機能+シナリオ(複数可)
• FeatureContext.php:テスト定義
• bootstrap配下はオートロードされる
く却 コマンド
• テスト
 – behat [features/*.feature]


• コンテキスト一覧
 – behat –dl


• スニペット生成
 – behat –f snippets
featureの
Feature: facebook login
  facebook login

  @javascript
  Scenario: facebook login
    Given on facebook login page.
    When input email and password.
    And     press login button
    Then facebook logged in.
Contextの
<?php

use Behat¥Behat¥Context¥ClosuredContextInterface,
  Behat¥Behat¥Context¥TranslatedContextInterface,
  Behat¥Behat¥Context¥BehatContext,
  Behat¥Behat¥Exception¥PendingException;
use Behat¥Gherkin¥Node¥PyStringNode,
  Behat¥Gherkin¥Node¥TableNode;

class FacebookloginContext extends BehatContext
{
   public $mink;

  public function __construct($mink)
  {
     $this->mink = $mink;
  }
(続く)
Contextの
  /**
   * @Given /^on facebook login page¥.$/
   */
  public function onFacebookLoginPage()
  {
     $this->mink->getSession()-
   >visit('http://www.facebook.com/login.php');
  }

  /**
   * @When /^input email and password¥.$/
   */
  public function inputEmailAndPassword()
  {
     $this->mink->getSession()->getPage()->fillField('email',
   MAIN_EMAIL);
     $this->mink->getSession()->getPage()->fillField('pass',
   PASSWORD);
  }
(続く)
Contextの
  /**
   * @Given /^press login button$/
   */
  public function pressLoginButton()
  {
     $this->mink->getSession()->getPage()->pressButton('Log In');
  }

  /**
   * @Then /^facebook logged in¥.$/
   */
  public function facebookLoggedIn()
  {
     assertEquals('https://www.facebook.com/', $this->mink-
   >getSession()->getCurrentUrl());
  }
}
(終わり)
FeatureContextの
<?php

use Behat¥Behat¥Context¥ClosuredContextInterface,
  Behat¥Behat¥Context¥TranslatedContextInterface,
  Behat¥Behat¥Context¥BehatContext,
  Behat¥Behat¥Exception¥PendingException;
use Behat¥Gherkin¥Node¥PyStringNode,
  Behat¥Gherkin¥Node¥TableNode;
use Behat¥MinkExtension¥Context¥MinkContext;

/**
 * Features context.
 */
class FeatureContext extends MinkContext
{

  public $base_url;
  public $mink;
FeatureContextの
     public function __construct(array $parameters)
    {
       // Initialize your context here
       $driver = new ¥Behat¥Mink¥Driver¥Selenium2Driver(
                    SELENIUM2_BROWSER, null, SELENIUM2_URL
       );
       $session = new ¥Behat¥Mink¥Session($driver);
       $this->base_url = OKKRU_BASE_URL;
       $mink = new ¥Behat¥Mink¥Mink();
       $mink->registerSession('okkru', $session);
       $mink->setDefaultSessionName('okkru');
       $this->mink = $mink;

        // use other context
        $this->useContext('fbconnect', new FbconnectContext($mink));
        $this->useContext('facebooklogin', new FacebookloginContext($mink));
        $this->useContext('sendme', new SendmeContext($mink));
        $this->useContext('inputme', new InputmeContext($mink));
        $this->useContext('ticketsend', new TicketsendContext($mink));
        $this->useContext('ticketrecipient', new TicketrecipientContext($mink));
    }

}
り             な           :feature
Feature: sendme
  商品を自分で受け取ることが出来る。

 @javascript
 Scenario: 商品を自分贈りで購入する。
   Given テスト用商品ページにアクセスする。
   When 購入ボタンを押下する。
   Then ログイン画面に遷移する。
   When ログインボタンを押下する。
   Then facebookログインページに遷移する。
   When facebookログインする。
   Then 友人選択画面に遷移する。
   When 友人選択画面で自分贈りを選択する。
   Then 自分の住所情報が入 出来る。
   And     FBから引いた情報が補完されている。
   When 自分の住所情報を入 する。
   And     確認ボタンを押下する。
   Then 確認画面に入       卣が勖単される。
   When 確定ボタンを押下する。
   Then 決済画面に遷移する。
り                    な               :Context
<?php

use Behat¥Behat¥Context¥ClosuredContextInterface,
  Behat¥Behat¥Context¥TranslatedContextInterface,
  Behat¥Behat¥Context¥BehatContext,
  Behat¥Behat¥Exception¥PendingException;
use Behat¥Gherkin¥Node¥PyStringNode,
  Behat¥Gherkin¥Node¥TableNode;

class SendmeContext extends BehatContext
{

  public $base_url;
  public $mink;

  public function __construct($mink)
  {
     $this->base_url = OKKRU_BASE_URL;
     $this->mink = $mink;
  }
(続く)
り                    な                :Context
/**
   * @Given /^テスト用商品ページにアクセスする。$/
   */
  public function accessDetail()
  {
      $this->mink->getSession()->visit($this->base_url .
   '/fbec_front/gift/detail/shop_id/' . SHOP_ID . '/product_id/' .
   PRODUCT_ID);
  }

  /**
   * @When /^購入ボタンを押下する。$/
   */
  public function pressProductButton()
  {
     $this->mink->getSession()->getPage()->clickLink('product-
   button');
  }
り                   な              :Context
/**
   * @Then /^ログイン画面に遷移する。$/
   */
  public function assertDetail2FBlogin()
  {
     $this->mink->assertSession()-
   >addressMatches("/fbec_front¥/gift¥/login¥/url/");
  }

  /**
   * @When /^ログインボタンを押下する。$/
   */
  public function pressConnectButton()
  {
     $this->mink->getSession()->wait(3000, "$('#login_btn').length
   > 0");
     $this->mink->getSession()->getPage()->clickLink('login_btn');
  }
り                         な                   :Context
/**
   * @Then /^facebookログインページに遷移する。$/
   */
  public function assertFBConnect2FBLogin()
  {
     $expected_url = 'https://www.facebook.com';
     $this->mink->getSession()->wait(3000);
     $actual_url = $this->mink->getSession()->getCurrentUrl();
     $this->getMainContext()->getSubContext('fbconnect')->assertContainUrl($expected_url,
    $actual_url);
  }

 /**
  * @When /^facebookログインする。$/
  */
 public function facebookLogin()
 {
    $this->getMainContext()->getSubContext('facebooklogin')->inputEmailAndPassword();
    $this->getMainContext()->getSubContext('facebooklogin')->pressLoginButton();
 }
り                  な               :Context
/**
   * @Then /^友人選択画面に遷移する。$/
   */
  public function displayFriendsSelect()
  {
     $this->mink->assertSession()-
   >addressMatches("/fbec_front¥/gift¥/friends¥/shop_id¥/" .
   SHOP_ID . "/");
  }

  /**
   * @When /^友人選択画面で自分贈りを選択する。$/
   */
  public function selectBuymyself()
  {
     $this->mink->getSession()->getPage()->clickLink('buymyself-
   button');
  }
り                       な                   :Context
/**
   * @Then /^自分の住所情報が入 出来る。$/
   */
  public function assertInputMyAddress()
  {
     $this->mink->assertSession()->pageTextContains('※贈り主情報:フリガナ');
     $this->mink->assertSession()->pageTextContains('※贈り主情報:メールアドレス');
     $this->mink->assertSession()->pageTextContains('※お届け先:   番号');
     $this->mink->assertSession()->pageTextContains('※お届け先:都道府県');
     $this->mink->assertSession()->pageTextContains('※お届け先:住所');
     $this->mink->assertSession()->pageTextContains('※お届け先:電話番号');
  }

 /**
  * @Given /^FBから引いた情報が補完されている。$/
  */
 public function assertSetFBinfo()
 {
    assertEquals(LAST_NAME_FB, $this->mink->getSession()->getPage()-
   >findById('last_name')->getValue());
    assertEquals(FIRST_NAME_FB, $this->mink->getSession()->getPage()-
   >findById('first_name')->getValue());
    assertEquals(MAIN_EMAIL, $this->mink->getSession()->getPage()->findById('email')-
   >getValue());
 }
り                              な                       :Context
/**
   * @When /^自分の住所情報を入 する。$/
   */
  public function inputMyAddress()
  {
     $this->mink->getSession()->getPage()->fillField('last_name', LAST_NAME_INPUT);
     $this->mink->getSession()->getPage()->fillField('first_name', FIRST_NAME_INPUT);
     $this->mink->getSession()->getPage()->fillField('last_name_kana', LAST_NAME_KANA);
     $this->mink->getSession()->getPage()->fillField('first_name_kana', FIRST_NAME_KANA);
     $this->mink->getSession()->getPage()->fillField('email', INPUT_EMAIL);
     $this->mink->getSession()->getPage()->fillField('zip3', ZIP3);
     $this->mink->getSession()->getPage()->fillField('zip4', ZIP4);
     $this->mink->getSession()->getPage()->selectFieldOption('prefecture', PREFECTURE);
     $this->mink->getSession()->getPage()->fillField('address', ADDRESS);
     $this->mink->getSession()->getPage()->fillField('address2', ADDRESS2);
     $this->mink->getSession()->getPage()->fillField('phone1', PHONE1);
     $this->mink->getSession()->getPage()->fillField('phone2', PHONE2);
     $this->mink->getSession()->getPage()->fillField('phone3', PHONE3);
     $this->mink->getSession()->getPage()->fillField('note', NOTE_SENDME);
  }

 /**
  * @Given /^確認ボタンを押下する。$/
  */
 public function pressSubmitShipmentButton()
 {
    $this->mink->getSession()->getPage()->clickLink('submit-shipment');
 }
り                       な                 :Context
/**
   * @Then /^確認画面に入             卣が勖単される。$/
   */
  public function assertDisplayInput()
  {
     $this->mink->assertSession()->pageTextContains(PRODUCT_NAME);
     $this->mink->assertSession()->pageTextContains(SHOP_NAME);
     $this->mink->assertSession()->pageTextContains(PRODUCT_PRICE);
     $this->mink->assertSession()->pageTextContains(PRODUCT_AND_WRAPPING_PRICE);
     $this->mink->assertSession()->pageTextContains(PRODUCT_ALL_PRICE);
     $this->mink->assertSession()->pageTextContains(LAST_NAME_INPUT . ' ' .
    FIRST_NAME_INPUT);
     $this->mink->assertSession()->pageTextContains(LAST_NAME_KANA . ' ' .
    FIRST_NAME_KANA);
     $this->mink->assertSession()->pageTextContains(INPUT_EMAIL);
     $this->mink->assertSession()->pageTextContains(ZIP3 . '-' . ZIP4);
     $this->mink->assertSession()->pageTextContains(PREFECTURE);
     $this->mink->assertSession()->pageTextContains(ADDRESS);
     $this->mink->assertSession()->pageTextContains(ADDRESS2);
     $this->mink->assertSession()->pageTextContains(PHONE1 . '-' . PHONE2 . '-' .
    PHONE3);
     $this->mink->assertSession()->pageTextContains(NOTE_SENDME);
  }
り                      な                   :Context
/**
   * @When /^確定ボタンを押下する。$/
   */
  public function pressSubmitConfirm()
  {
     $this->mink->getSession()->getPage()->clickLink('submit-confirm');
  }

    /**
     * @Then /^決済画面に遷移する。$/
     */
    public function assertConfirm2SBPS()
    {
       $this->mink->getSession()->wait(5000, 'typeof window.jQuery == "function"');
       $this->mink->getSession()->wait(3000, 'window.document.getElementById("#title") >
      0');
       $this->mink->assertSession()->addressMatches("/¥/f01¥/FepBuyInfoReceive.do/");
    }

}
でも。
まとめ
• メリット
  – BDDで「なんちゃって」アジャイルを回避
  – behatでテストファーストすることで事前の洗い出しが
         に


• デメリット
  – スケジュールに追われる場合後回しになりがちで開発
    プロセスを徹底するのが難しい
  – CIサーバに る定期  でアンドン化して 続メンテ
    ナンスしないと無効なテストケースが増殖
\(^o^)/オワタ
  facebook/twitterアカウント:tchikuba

More Related Content

What's hot

Behatで行う、E2Eテスト入門
Behatで行う、E2Eテスト入門Behatで行う、E2Eテスト入門
Behatで行う、E2Eテスト入門leverages_event
 
야, 너두 짤수있어 - IaC Basic(210131 김성익)
야, 너두 짤수있어 - IaC Basic(210131 김성익)야, 너두 짤수있어 - IaC Basic(210131 김성익)
야, 너두 짤수있어 - IaC Basic(210131 김성익)SeongIkKim2
 
PHPの戻り値型宣言でselfを使ってみよう
PHPの戻り値型宣言でselfを使ってみようPHPの戻り値型宣言でselfを使ってみよう
PHPの戻り値型宣言でselfを使ってみようDQNEO
 
Clean Architecture for Unity
Clean Architecture for UnityClean Architecture for Unity
Clean Architecture for UnityMori Tetsuya
 
はじめようGit
はじめようGitはじめようGit
はじめようGittechscore
 
Xamarin.Forms.WPF を試してみた
Xamarin.Forms.WPF を試してみたXamarin.Forms.WPF を試してみた
Xamarin.Forms.WPF を試してみたm ishizaki
 
ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術
ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術
ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術Masahiro Nagano
 
The Best (and Worst) of Django
The Best (and Worst) of DjangoThe Best (and Worst) of Django
The Best (and Worst) of DjangoJacob Kaplan-Moss
 
Prometheus × container insightsで aksを監視してみた
Prometheus × container insightsで aksを監視してみたPrometheus × container insightsで aksを監視してみた
Prometheus × container insightsで aksを監視してみたTaichiSugibe
 
SpringBootにおけるテンプレートエンジンの活用
SpringBootにおけるテンプレートエンジンの活用SpringBootにおけるテンプレートエンジンの活用
SpringBootにおけるテンプレートエンジンの活用iPride Co., Ltd.
 
Yocto Project ハンズオン プレゼン用資料
Yocto Project ハンズオン プレゼン用資料Yocto Project ハンズオン プレゼン用資料
Yocto Project ハンズオン プレゼン用資料Nobuhiro Iwamatsu
 
Laravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのかLaravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのかShohei Okada
 
Redmineとgitの 連携利用事例
Redmineとgitの 連携利用事例Redmineとgitの 連携利用事例
Redmineとgitの 連携利用事例Tomohisa Kusukawa
 
자바 웹프로젝트 개발환경 셋팅
자바 웹프로젝트 개발환경 셋팅자바 웹프로젝트 개발환경 셋팅
자바 웹프로젝트 개발환경 셋팅Yoonsung Jung
 
Laravelとテストについて
LaravelとテストについてLaravelとテストについて
LaravelとテストについてTakeo Noda
 
GoによるiOSアプリの開発
GoによるiOSアプリの開発GoによるiOSアプリの開発
GoによるiOSアプリの開発Takuya Ueda
 
Reactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単にReactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単にYoshifumi Kawai
 
ツイートボタンから画像付きツイートをツイートさせる方法
ツイートボタンから画像付きツイートをツイートさせる方法ツイートボタンから画像付きツイートをツイートさせる方法
ツイートボタンから画像付きツイートをツイートさせる方法Akira Fukuoka
 

What's hot (20)

Behatで行う、E2Eテスト入門
Behatで行う、E2Eテスト入門Behatで行う、E2Eテスト入門
Behatで行う、E2Eテスト入門
 
야, 너두 짤수있어 - IaC Basic(210131 김성익)
야, 너두 짤수있어 - IaC Basic(210131 김성익)야, 너두 짤수있어 - IaC Basic(210131 김성익)
야, 너두 짤수있어 - IaC Basic(210131 김성익)
 
PHPの戻り値型宣言でselfを使ってみよう
PHPの戻り値型宣言でselfを使ってみようPHPの戻り値型宣言でselfを使ってみよう
PHPの戻り値型宣言でselfを使ってみよう
 
Clean Architecture for Unity
Clean Architecture for UnityClean Architecture for Unity
Clean Architecture for Unity
 
はじめようGit
はじめようGitはじめようGit
はじめようGit
 
Xamarin.Forms.WPF を試してみた
Xamarin.Forms.WPF を試してみたXamarin.Forms.WPF を試してみた
Xamarin.Forms.WPF を試してみた
 
C# 9.0 / .NET 5.0
C# 9.0 / .NET 5.0C# 9.0 / .NET 5.0
C# 9.0 / .NET 5.0
 
ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術
ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術
ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術
 
The Best (and Worst) of Django
The Best (and Worst) of DjangoThe Best (and Worst) of Django
The Best (and Worst) of Django
 
Prometheus × container insightsで aksを監視してみた
Prometheus × container insightsで aksを監視してみたPrometheus × container insightsで aksを監視してみた
Prometheus × container insightsで aksを監視してみた
 
SpringBootにおけるテンプレートエンジンの活用
SpringBootにおけるテンプレートエンジンの活用SpringBootにおけるテンプレートエンジンの活用
SpringBootにおけるテンプレートエンジンの活用
 
Yocto Project ハンズオン プレゼン用資料
Yocto Project ハンズオン プレゼン用資料Yocto Project ハンズオン プレゼン用資料
Yocto Project ハンズオン プレゼン用資料
 
Jenkins と groovy
Jenkins と groovyJenkins と groovy
Jenkins と groovy
 
Laravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのかLaravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのか
 
Redmineとgitの 連携利用事例
Redmineとgitの 連携利用事例Redmineとgitの 連携利用事例
Redmineとgitの 連携利用事例
 
자바 웹프로젝트 개발환경 셋팅
자바 웹프로젝트 개발환경 셋팅자바 웹프로젝트 개발환경 셋팅
자바 웹프로젝트 개발환경 셋팅
 
Laravelとテストについて
LaravelとテストについてLaravelとテストについて
Laravelとテストについて
 
GoによるiOSアプリの開発
GoによるiOSアプリの開発GoによるiOSアプリの開発
GoによるiOSアプリの開発
 
Reactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単にReactive Extensionsで非同期処理を簡単に
Reactive Extensionsで非同期処理を簡単に
 
ツイートボタンから画像付きツイートをツイートさせる方法
ツイートボタンから画像付きツイートをツイートさせる方法ツイートボタンから画像付きツイートをツイートさせる方法
ツイートボタンから画像付きツイートをツイートさせる方法
 

Viewers also liked

Behat+Symfony2ではじめるBDD超入門
Behat+Symfony2ではじめるBDD超入門Behat+Symfony2ではじめるBDD超入門
Behat+Symfony2ではじめるBDD超入門晃 遠山
 
「スピード」と「品質」を実現するPHP開発チームの取り組み~AngularJS+FuelPHP+AspectMock~
「スピード」と「品質」を実現するPHP開発チームの取り組み~AngularJS+FuelPHP+AspectMock~「スピード」と「品質」を実現するPHP開発チームの取り組み~AngularJS+FuelPHP+AspectMock~
「スピード」と「品質」を実現するPHP開発チームの取り組み~AngularJS+FuelPHP+AspectMock~leverages_event
 
phpspecで始めるBDD
phpspecで始めるBDDphpspecで始めるBDD
phpspecで始めるBDDYuuki Takezawa
 
Codeceptionの受け入れテストをマネる
Codeceptionの受け入れテストをマネるCodeceptionの受け入れテストをマネる
Codeceptionの受け入れテストをマネるinfinite_loop
 
TDDBC Fukuoka Day1
TDDBC Fukuoka Day1TDDBC Fukuoka Day1
TDDBC Fukuoka Day1Takuto Wada
 
テスト自動化ツール[Selenium]を検討してみて
テスト自動化ツール[Selenium]を検討してみてテスト自動化ツール[Selenium]を検討してみて
テスト自動化ツール[Selenium]を検討してみて裕史 川松
 
bashでWebブラウザ(Selenium WebDriver)を動かした話
bashでWebブラウザ(Selenium WebDriver)を動かした話bashでWebブラウザ(Selenium WebDriver)を動かした話
bashでWebブラウザ(Selenium WebDriver)を動かした話洋史 東平
 
Scrutinizer CIでPHPも静的解析 #phpstudy
Scrutinizer CIでPHPも静的解析 #phpstudyScrutinizer CIでPHPも静的解析 #phpstudy
Scrutinizer CIでPHPも静的解析 #phpstudyHiraku Nakano
 
最強のPHP統合開発環境 PHPStorm
最強のPHP統合開発環境 PHPStorm最強のPHP統合開発環境 PHPStorm
最強のPHP統合開発環境 PHPStorm晃 遠山
 
はじめてのUser-Agent文字列
はじめてのUser-Agent文字列はじめてのUser-Agent文字列
はじめてのUser-Agent文字列Kenta USAMI
 
Codeceptionことはじめ
CodeceptionことはじめCodeceptionことはじめ
Codeceptionことはじめinfinite_loop
 
「Selenium実践入門」で学ぶテスト自動化の世界
「Selenium実践入門」で学ぶテスト自動化の世界「Selenium実践入門」で学ぶテスト自動化の世界
「Selenium実践入門」で学ぶテスト自動化の世界Nozomi Ito
 
5分でわかる静的解析入門
5分でわかる静的解析入門5分でわかる静的解析入門
5分でわかる静的解析入門Kenta USAMI
 
たのしい独自フレームワーク
たのしい独自フレームワークたのしい独自フレームワーク
たのしい独自フレームワークKenta USAMI
 
いつでも聞けるTDD入門 #TDDBC_NAGOYA
いつでも聞けるTDD入門 #TDDBC_NAGOYAいつでも聞けるTDD入門 #TDDBC_NAGOYA
いつでも聞けるTDD入門 #TDDBC_NAGOYAkyon mm
 
今、最もイケてるPHPフレームワークLaravel4
今、最もイケてるPHPフレームワークLaravel4今、最もイケてるPHPフレームワークLaravel4
今、最もイケてるPHPフレームワークLaravel4アシアル株式会社
 
脆弱性もバグ、だからテストしよう PHPカンファンレス2015
脆弱性もバグ、だからテストしよう PHPカンファンレス2015脆弱性もバグ、だからテストしよう PHPカンファンレス2015
脆弱性もバグ、だからテストしよう PHPカンファンレス2015ichikaway
 
AWS October Webinar Series - Introducing Amazon Elasticsearch Service
AWS October Webinar Series - Introducing Amazon Elasticsearch ServiceAWS October Webinar Series - Introducing Amazon Elasticsearch Service
AWS October Webinar Series - Introducing Amazon Elasticsearch ServiceAmazon Web Services
 
今さら聞けない人のためのDevOps超入門
今さら聞けない人のためのDevOps超入門今さら聞けない人のためのDevOps超入門
今さら聞けない人のためのDevOps超入門VirtualTech Japan Inc.
 

Viewers also liked (20)

Behat+Symfony2ではじめるBDD超入門
Behat+Symfony2ではじめるBDD超入門Behat+Symfony2ではじめるBDD超入門
Behat+Symfony2ではじめるBDD超入門
 
「スピード」と「品質」を実現するPHP開発チームの取り組み~AngularJS+FuelPHP+AspectMock~
「スピード」と「品質」を実現するPHP開発チームの取り組み~AngularJS+FuelPHP+AspectMock~「スピード」と「品質」を実現するPHP開発チームの取り組み~AngularJS+FuelPHP+AspectMock~
「スピード」と「品質」を実現するPHP開発チームの取り組み~AngularJS+FuelPHP+AspectMock~
 
phpspecで始めるBDD
phpspecで始めるBDDphpspecで始めるBDD
phpspecで始めるBDD
 
Codeceptionの受け入れテストをマネる
Codeceptionの受け入れテストをマネるCodeceptionの受け入れテストをマネる
Codeceptionの受け入れテストをマネる
 
TDDBC Fukuoka Day1
TDDBC Fukuoka Day1TDDBC Fukuoka Day1
TDDBC Fukuoka Day1
 
BPStudy20121221
BPStudy20121221BPStudy20121221
BPStudy20121221
 
テスト自動化ツール[Selenium]を検討してみて
テスト自動化ツール[Selenium]を検討してみてテスト自動化ツール[Selenium]を検討してみて
テスト自動化ツール[Selenium]を検討してみて
 
bashでWebブラウザ(Selenium WebDriver)を動かした話
bashでWebブラウザ(Selenium WebDriver)を動かした話bashでWebブラウザ(Selenium WebDriver)を動かした話
bashでWebブラウザ(Selenium WebDriver)を動かした話
 
Scrutinizer CIでPHPも静的解析 #phpstudy
Scrutinizer CIでPHPも静的解析 #phpstudyScrutinizer CIでPHPも静的解析 #phpstudy
Scrutinizer CIでPHPも静的解析 #phpstudy
 
最強のPHP統合開発環境 PHPStorm
最強のPHP統合開発環境 PHPStorm最強のPHP統合開発環境 PHPStorm
最強のPHP統合開発環境 PHPStorm
 
はじめてのUser-Agent文字列
はじめてのUser-Agent文字列はじめてのUser-Agent文字列
はじめてのUser-Agent文字列
 
Codeceptionことはじめ
CodeceptionことはじめCodeceptionことはじめ
Codeceptionことはじめ
 
「Selenium実践入門」で学ぶテスト自動化の世界
「Selenium実践入門」で学ぶテスト自動化の世界「Selenium実践入門」で学ぶテスト自動化の世界
「Selenium実践入門」で学ぶテスト自動化の世界
 
5分でわかる静的解析入門
5分でわかる静的解析入門5分でわかる静的解析入門
5分でわかる静的解析入門
 
たのしい独自フレームワーク
たのしい独自フレームワークたのしい独自フレームワーク
たのしい独自フレームワーク
 
いつでも聞けるTDD入門 #TDDBC_NAGOYA
いつでも聞けるTDD入門 #TDDBC_NAGOYAいつでも聞けるTDD入門 #TDDBC_NAGOYA
いつでも聞けるTDD入門 #TDDBC_NAGOYA
 
今、最もイケてるPHPフレームワークLaravel4
今、最もイケてるPHPフレームワークLaravel4今、最もイケてるPHPフレームワークLaravel4
今、最もイケてるPHPフレームワークLaravel4
 
脆弱性もバグ、だからテストしよう PHPカンファンレス2015
脆弱性もバグ、だからテストしよう PHPカンファンレス2015脆弱性もバグ、だからテストしよう PHPカンファンレス2015
脆弱性もバグ、だからテストしよう PHPカンファンレス2015
 
AWS October Webinar Series - Introducing Amazon Elasticsearch Service
AWS October Webinar Series - Introducing Amazon Elasticsearch ServiceAWS October Webinar Series - Introducing Amazon Elasticsearch Service
AWS October Webinar Series - Introducing Amazon Elasticsearch Service
 
今さら聞けない人のためのDevOps超入門
今さら聞けない人のためのDevOps超入門今さら聞けない人のためのDevOps超入門
今さら聞けない人のためのDevOps超入門
 

Similar to behatで始めるBDD

omoon.org の裏側 〜FuelPHP の task 活用例〜
omoon.org の裏側 〜FuelPHP の task 活用例〜omoon.org の裏側 〜FuelPHP の task 活用例〜
omoon.org の裏側 〜FuelPHP の task 活用例〜Sotaro Omura
 
WordPressで提供するWeb API
WordPressで提供するWeb APIWordPressで提供するWeb API
WordPressで提供するWeb APIYuko Toriyama
 
Mojoliciousをウェブ制作現場で使ってみてる
Mojoliciousをウェブ制作現場で使ってみてるMojoliciousをウェブ制作現場で使ってみてる
Mojoliciousをウェブ制作現場で使ってみてるjamadam
 
3ヶ月でリア充大学生がFBアプリをリリースするまで @macrocro
3ヶ月でリア充大学生がFBアプリをリリースするまで @macrocro3ヶ月でリア充大学生がFBアプリをリリースするまで @macrocro
3ヶ月でリア充大学生がFBアプリをリリースするまで @macrocroYuuki Kuroda
 
WordBech Osaka No.28
WordBech Osaka No.28WordBech Osaka No.28
WordBech Osaka No.28Kite Koga
 
リアルFacebookガジェットを作った(ロングバージョン)
リアルFacebookガジェットを作った(ロングバージョン)リアルFacebookガジェットを作った(ロングバージョン)
リアルFacebookガジェットを作った(ロングバージョン)Mariko Goda
 
「Windows 8 ストア アプリ開発 tips」 hokuriku.net vol.11 (2013年1月26日)
「Windows 8 ストア アプリ開発 tips」  hokuriku.net vol.11 (2013年1月26日)「Windows 8 ストア アプリ開発 tips」  hokuriku.net vol.11 (2013年1月26日)
「Windows 8 ストア アプリ開発 tips」 hokuriku.net vol.11 (2013年1月26日)Fujio Kojima
 
WordBench京都 9月号:kintone×WordPressハンズオン
WordBench京都 9月号:kintone×WordPressハンズオンWordBench京都 9月号:kintone×WordPressハンズオン
WordBench京都 9月号:kintone×WordPressハンズオンTakashi Hosoya
 
FuelPHPをさわってみて
FuelPHPをさわってみてFuelPHPをさわってみて
FuelPHPをさわってみてSotaro Omura
 
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsug
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsugSpringOne 2GX 2014 参加報告 & Spring 4.1について #jsug
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsugToshiaki Maki
 
モバイル開発@symfony
モバイル開発@symfonyモバイル開発@symfony
モバイル開発@symfonyDaichi Kamemoto
 
[東京] JapanSharePointGroup 勉強会 #2
[東京] JapanSharePointGroup 勉強会 #2[東京] JapanSharePointGroup 勉強会 #2
[東京] JapanSharePointGroup 勉強会 #2Atsuo Yamasaki
 
WordPress widget api
WordPress widget apiWordPress widget api
WordPress widget apiTakami Kazuya
 
SocialWeb Conference vol.5 OpenSocial Night #2
SocialWeb Conference vol.5 OpenSocial Night #2SocialWeb Conference vol.5 OpenSocial Night #2
SocialWeb Conference vol.5 OpenSocial Night #2Nobuhiro Nakajima
 
初めての Data api
初めての Data api初めての Data api
初めての Data apiYuji Takayama
 
Data apiで実現 進化するwebの世界
Data apiで実現 進化するwebの世界Data apiで実現 進化するwebの世界
Data apiで実現 進化するwebの世界Yuji Takayama
 

Similar to behatで始めるBDD (20)

omoon.org の裏側 〜FuelPHP の task 活用例〜
omoon.org の裏側 〜FuelPHP の task 活用例〜omoon.org の裏側 〜FuelPHP の task 活用例〜
omoon.org の裏側 〜FuelPHP の task 活用例〜
 
Try Jetpack
Try JetpackTry Jetpack
Try Jetpack
 
WordPressで提供するWeb API
WordPressで提供するWeb APIWordPressで提供するWeb API
WordPressで提供するWeb API
 
Mojoliciousをウェブ制作現場で使ってみてる
Mojoliciousをウェブ制作現場で使ってみてるMojoliciousをウェブ制作現場で使ってみてる
Mojoliciousをウェブ制作現場で使ってみてる
 
Inside Movable Type
Inside Movable TypeInside Movable Type
Inside Movable Type
 
3ヶ月でリア充大学生がFBアプリをリリースするまで @macrocro
3ヶ月でリア充大学生がFBアプリをリリースするまで @macrocro3ヶ月でリア充大学生がFBアプリをリリースするまで @macrocro
3ヶ月でリア充大学生がFBアプリをリリースするまで @macrocro
 
Ci tutorial
Ci tutorialCi tutorial
Ci tutorial
 
WordBech Osaka No.28
WordBech Osaka No.28WordBech Osaka No.28
WordBech Osaka No.28
 
リアルFacebookガジェットを作った(ロングバージョン)
リアルFacebookガジェットを作った(ロングバージョン)リアルFacebookガジェットを作った(ロングバージョン)
リアルFacebookガジェットを作った(ロングバージョン)
 
「Windows 8 ストア アプリ開発 tips」 hokuriku.net vol.11 (2013年1月26日)
「Windows 8 ストア アプリ開発 tips」  hokuriku.net vol.11 (2013年1月26日)「Windows 8 ストア アプリ開発 tips」  hokuriku.net vol.11 (2013年1月26日)
「Windows 8 ストア アプリ開発 tips」 hokuriku.net vol.11 (2013年1月26日)
 
WordBench京都 9月号:kintone×WordPressハンズオン
WordBench京都 9月号:kintone×WordPressハンズオンWordBench京都 9月号:kintone×WordPressハンズオン
WordBench京都 9月号:kintone×WordPressハンズオン
 
FuelPHPをさわってみて
FuelPHPをさわってみてFuelPHPをさわってみて
FuelPHPをさわってみて
 
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsug
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsugSpringOne 2GX 2014 参加報告 & Spring 4.1について #jsug
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsug
 
モバイル開発@symfony
モバイル開発@symfonyモバイル開発@symfony
モバイル開発@symfony
 
[東京] JapanSharePointGroup 勉強会 #2
[東京] JapanSharePointGroup 勉強会 #2[東京] JapanSharePointGroup 勉強会 #2
[東京] JapanSharePointGroup 勉強会 #2
 
WordPress widget api
WordPress widget apiWordPress widget api
WordPress widget api
 
test
testtest
test
 
SocialWeb Conference vol.5 OpenSocial Night #2
SocialWeb Conference vol.5 OpenSocial Night #2SocialWeb Conference vol.5 OpenSocial Night #2
SocialWeb Conference vol.5 OpenSocial Night #2
 
初めての Data api
初めての Data api初めての Data api
初めての Data api
 
Data apiで実現 進化するwebの世界
Data apiで実現 進化するwebの世界Data apiで実現 進化するwebの世界
Data apiで実現 進化するwebの世界
 

More from Tsutomu Chikuba

Ebisu.rb#15LT「turnipいいよturnip」
Ebisu.rb#15LT「turnipいいよturnip」Ebisu.rb#15LT「turnipいいよturnip」
Ebisu.rb#15LT「turnipいいよturnip」Tsutomu Chikuba
 
Meguro.rb#3LT「Ruby入門書を書いてて得られた知見5選+3α」
Meguro.rb#3LT「Ruby入門書を書いてて得られた知見5選+3α」Meguro.rb#3LT「Ruby入門書を書いてて得られた知見5選+3α」
Meguro.rb#3LT「Ruby入門書を書いてて得られた知見5選+3α」Tsutomu Chikuba
 
オープンデータ利活用への道のり@未来型不動産サービス「IESHIL(イエシル)」の事例
オープンデータ利活用への道のり@未来型不動産サービス「IESHIL(イエシル)」の事例オープンデータ利活用への道のり@未来型不動産サービス「IESHIL(イエシル)」の事例
オープンデータ利活用への道のり@未来型不動産サービス「IESHIL(イエシル)」の事例Tsutomu Chikuba
 
turnipとcapybaraとBDDと私
turnipとcapybaraとBDDと私turnipとcapybaraとBDDと私
turnipとcapybaraとBDDと私Tsutomu Chikuba
 
いよいよPHPerもリーンで行こう
いよいよPHPerもリーンで行こういよいよPHPerもリーンで行こう
いよいよPHPerもリーンで行こうTsutomu Chikuba
 
Php unit extensions_selenium2_testcaseによる結合試験でらくらくテスト♪
Php unit extensions_selenium2_testcaseによる結合試験でらくらくテスト♪Php unit extensions_selenium2_testcaseによる結合試験でらくらくテスト♪
Php unit extensions_selenium2_testcaseによる結合試験でらくらくテスト♪Tsutomu Chikuba
 
ビジネス的に高価値なアジャイルテスト
ビジネス的に高価値なアジャイルテストビジネス的に高価値なアジャイルテスト
ビジネス的に高価値なアジャイルテストTsutomu Chikuba
 
【参観レポート】Lean startupnight real startup dialog
【参観レポート】Lean startupnight   real startup dialog【参観レポート】Lean startupnight   real startup dialog
【参観レポート】Lean startupnight real startup dialogTsutomu Chikuba
 
リーンソフトウェア開発で始めるFacebookアプリ開発
リーンソフトウェア開発で始めるFacebookアプリ開発リーンソフトウェア開発で始めるFacebookアプリ開発
リーンソフトウェア開発で始めるFacebookアプリ開発Tsutomu Chikuba
 

More from Tsutomu Chikuba (11)

Megurorb 15 lt
Megurorb 15 ltMegurorb 15 lt
Megurorb 15 lt
 
Ebisu.rb#15LT「turnipいいよturnip」
Ebisu.rb#15LT「turnipいいよturnip」Ebisu.rb#15LT「turnipいいよturnip」
Ebisu.rb#15LT「turnipいいよturnip」
 
Meguro.rb#3LT「Ruby入門書を書いてて得られた知見5選+3α」
Meguro.rb#3LT「Ruby入門書を書いてて得られた知見5選+3α」Meguro.rb#3LT「Ruby入門書を書いてて得られた知見5選+3α」
Meguro.rb#3LT「Ruby入門書を書いてて得られた知見5選+3α」
 
オープンデータ利活用への道のり@未来型不動産サービス「IESHIL(イエシル)」の事例
オープンデータ利活用への道のり@未来型不動産サービス「IESHIL(イエシル)」の事例オープンデータ利活用への道のり@未来型不動産サービス「IESHIL(イエシル)」の事例
オープンデータ利活用への道のり@未来型不動産サービス「IESHIL(イエシル)」の事例
 
turnipとcapybaraとBDDと私
turnipとcapybaraとBDDと私turnipとcapybaraとBDDと私
turnipとcapybaraとBDDと私
 
いよいよPHPerもリーンで行こう
いよいよPHPerもリーンで行こういよいよPHPerもリーンで行こう
いよいよPHPerもリーンで行こう
 
Php unit extensions_selenium2_testcaseによる結合試験でらくらくテスト♪
Php unit extensions_selenium2_testcaseによる結合試験でらくらくテスト♪Php unit extensions_selenium2_testcaseによる結合試験でらくらくテスト♪
Php unit extensions_selenium2_testcaseによる結合試験でらくらくテスト♪
 
ビジネス的に高価値なアジャイルテスト
ビジネス的に高価値なアジャイルテストビジネス的に高価値なアジャイルテスト
ビジネス的に高価値なアジャイルテスト
 
【参観レポート】Lean startupnight real startup dialog
【参観レポート】Lean startupnight   real startup dialog【参観レポート】Lean startupnight   real startup dialog
【参観レポート】Lean startupnight real startup dialog
 
PHP agile test tips
PHP agile test tipsPHP agile test tips
PHP agile test tips
 
リーンソフトウェア開発で始めるFacebookアプリ開発
リーンソフトウェア開発で始めるFacebookアプリ開発リーンソフトウェア開発で始めるFacebookアプリ開発
リーンソフトウェア開発で始めるFacebookアプリ開発
 

Recently uploaded

【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)Hiroki Ichikura
 
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案sugiuralab
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNetToru Tamaki
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Yuma Ohgami
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものですiPride Co., Ltd.
 
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfクラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfFumieNakayama
 
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)UEHARA, Tetsutaro
 
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfAWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfFumieNakayama
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...Toru Tamaki
 
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...博三 太田
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdftaisei2219
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A surveyToru Tamaki
 

Recently uploaded (12)

【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
 
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものです
 
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfクラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
 
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
 
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfAWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
 
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdf
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey
 

behatで始めるBDD

  • 1. 第65回 PHP勉強会 @東京(Engine Yard) behat/PHPUnitで始める BDD/TDD 2013/02/28(木) @ビルコム
  • 3. about tchikuba • 所属 – ビルコム株式会社 • 自社サービス – ReBuy http://rebuy.jp/ – Okkru https://okkru.jp • 役割 – 開発Playing Manager • いいね! – Linux、ビール、宇宙平和 • facebook/twitter – tchikuba
  • 6. 我々の諸環境 • OS:CentOS(nifty cloud) • Webサーバ:Nginx/Apache • DBサーバ:MySQL • CIサーバ:Jenkins/SeleniumServer • 言語:PHP • フレームワーク:Zendframework • フロント:jQuery(Mobile) • SCM:Git • BTS:Backlog
  • 9. TDDとは • Test-Driven Developmentの • 和訳:テスト駆動開発 • 特徴 – テストファースト – リファクタリング • メリット – スパゲッティの塩分低下 – 開発アジリティ上昇
  • 10. BDDとは • Behavior-Driven Developmentの • 和訳:振舞駆動開発 • 特徴 – 自然言語 – 要求仕様(スペック) • メリット – け れ 厙 – オブジェクト指向強化
  • 11. BDD/TDDのフレームワーク • BDD – behat + mink – PHPSpec – Selenium • TDD – PHPUnit
  • 13.
  • 15. behat環境設定 • インストール (PHP5.3.4 ≧推奨) – Composer • vi composer.json • curl http://getcomposer.org/installer | php • php composer.phar install – PHAR – Git • 初期プロジェクト生成 – behat --init
  • 16. ディレクトリ構成 • behat_root/ – features/ • bootstrap/ – FeatureContext.php • *.feature – behat.yml – build.xml *for Jenkins • *.feature:機能+シナリオ(複数可) • FeatureContext.php:テスト定義 • bootstrap配下はオートロードされる
  • 17. く却 コマンド • テスト – behat [features/*.feature] • コンテキスト一覧 – behat –dl • スニペット生成 – behat –f snippets
  • 18. featureの Feature: facebook login facebook login @javascript Scenario: facebook login Given on facebook login page. When input email and password. And press login button Then facebook logged in.
  • 19. Contextの <?php use Behat¥Behat¥Context¥ClosuredContextInterface, Behat¥Behat¥Context¥TranslatedContextInterface, Behat¥Behat¥Context¥BehatContext, Behat¥Behat¥Exception¥PendingException; use Behat¥Gherkin¥Node¥PyStringNode, Behat¥Gherkin¥Node¥TableNode; class FacebookloginContext extends BehatContext { public $mink; public function __construct($mink) { $this->mink = $mink; } (続く)
  • 20. Contextの /** * @Given /^on facebook login page¥.$/ */ public function onFacebookLoginPage() { $this->mink->getSession()- >visit('http://www.facebook.com/login.php'); } /** * @When /^input email and password¥.$/ */ public function inputEmailAndPassword() { $this->mink->getSession()->getPage()->fillField('email', MAIN_EMAIL); $this->mink->getSession()->getPage()->fillField('pass', PASSWORD); } (続く)
  • 21. Contextの /** * @Given /^press login button$/ */ public function pressLoginButton() { $this->mink->getSession()->getPage()->pressButton('Log In'); } /** * @Then /^facebook logged in¥.$/ */ public function facebookLoggedIn() { assertEquals('https://www.facebook.com/', $this->mink- >getSession()->getCurrentUrl()); } } (終わり)
  • 22. FeatureContextの <?php use Behat¥Behat¥Context¥ClosuredContextInterface, Behat¥Behat¥Context¥TranslatedContextInterface, Behat¥Behat¥Context¥BehatContext, Behat¥Behat¥Exception¥PendingException; use Behat¥Gherkin¥Node¥PyStringNode, Behat¥Gherkin¥Node¥TableNode; use Behat¥MinkExtension¥Context¥MinkContext; /** * Features context. */ class FeatureContext extends MinkContext { public $base_url; public $mink;
  • 23. FeatureContextの public function __construct(array $parameters) { // Initialize your context here $driver = new ¥Behat¥Mink¥Driver¥Selenium2Driver( SELENIUM2_BROWSER, null, SELENIUM2_URL ); $session = new ¥Behat¥Mink¥Session($driver); $this->base_url = OKKRU_BASE_URL; $mink = new ¥Behat¥Mink¥Mink(); $mink->registerSession('okkru', $session); $mink->setDefaultSessionName('okkru'); $this->mink = $mink; // use other context $this->useContext('fbconnect', new FbconnectContext($mink)); $this->useContext('facebooklogin', new FacebookloginContext($mink)); $this->useContext('sendme', new SendmeContext($mink)); $this->useContext('inputme', new InputmeContext($mink)); $this->useContext('ticketsend', new TicketsendContext($mink)); $this->useContext('ticketrecipient', new TicketrecipientContext($mink)); } }
  • 24. な :feature Feature: sendme 商品を自分で受け取ることが出来る。 @javascript Scenario: 商品を自分贈りで購入する。 Given テスト用商品ページにアクセスする。 When 購入ボタンを押下する。 Then ログイン画面に遷移する。 When ログインボタンを押下する。 Then facebookログインページに遷移する。 When facebookログインする。 Then 友人選択画面に遷移する。 When 友人選択画面で自分贈りを選択する。 Then 自分の住所情報が入 出来る。 And FBから引いた情報が補完されている。 When 自分の住所情報を入 する。 And 確認ボタンを押下する。 Then 確認画面に入 卣が勖単される。 When 確定ボタンを押下する。 Then 決済画面に遷移する。
  • 25. な :Context <?php use Behat¥Behat¥Context¥ClosuredContextInterface, Behat¥Behat¥Context¥TranslatedContextInterface, Behat¥Behat¥Context¥BehatContext, Behat¥Behat¥Exception¥PendingException; use Behat¥Gherkin¥Node¥PyStringNode, Behat¥Gherkin¥Node¥TableNode; class SendmeContext extends BehatContext { public $base_url; public $mink; public function __construct($mink) { $this->base_url = OKKRU_BASE_URL; $this->mink = $mink; } (続く)
  • 26. な :Context /** * @Given /^テスト用商品ページにアクセスする。$/ */ public function accessDetail() { $this->mink->getSession()->visit($this->base_url . '/fbec_front/gift/detail/shop_id/' . SHOP_ID . '/product_id/' . PRODUCT_ID); } /** * @When /^購入ボタンを押下する。$/ */ public function pressProductButton() { $this->mink->getSession()->getPage()->clickLink('product- button'); }
  • 27. な :Context /** * @Then /^ログイン画面に遷移する。$/ */ public function assertDetail2FBlogin() { $this->mink->assertSession()- >addressMatches("/fbec_front¥/gift¥/login¥/url/"); } /** * @When /^ログインボタンを押下する。$/ */ public function pressConnectButton() { $this->mink->getSession()->wait(3000, "$('#login_btn').length > 0"); $this->mink->getSession()->getPage()->clickLink('login_btn'); }
  • 28. な :Context /** * @Then /^facebookログインページに遷移する。$/ */ public function assertFBConnect2FBLogin() { $expected_url = 'https://www.facebook.com'; $this->mink->getSession()->wait(3000); $actual_url = $this->mink->getSession()->getCurrentUrl(); $this->getMainContext()->getSubContext('fbconnect')->assertContainUrl($expected_url, $actual_url); } /** * @When /^facebookログインする。$/ */ public function facebookLogin() { $this->getMainContext()->getSubContext('facebooklogin')->inputEmailAndPassword(); $this->getMainContext()->getSubContext('facebooklogin')->pressLoginButton(); }
  • 29. な :Context /** * @Then /^友人選択画面に遷移する。$/ */ public function displayFriendsSelect() { $this->mink->assertSession()- >addressMatches("/fbec_front¥/gift¥/friends¥/shop_id¥/" . SHOP_ID . "/"); } /** * @When /^友人選択画面で自分贈りを選択する。$/ */ public function selectBuymyself() { $this->mink->getSession()->getPage()->clickLink('buymyself- button'); }
  • 30. な :Context /** * @Then /^自分の住所情報が入 出来る。$/ */ public function assertInputMyAddress() { $this->mink->assertSession()->pageTextContains('※贈り主情報:フリガナ'); $this->mink->assertSession()->pageTextContains('※贈り主情報:メールアドレス'); $this->mink->assertSession()->pageTextContains('※お届け先: 番号'); $this->mink->assertSession()->pageTextContains('※お届け先:都道府県'); $this->mink->assertSession()->pageTextContains('※お届け先:住所'); $this->mink->assertSession()->pageTextContains('※お届け先:電話番号'); } /** * @Given /^FBから引いた情報が補完されている。$/ */ public function assertSetFBinfo() { assertEquals(LAST_NAME_FB, $this->mink->getSession()->getPage()- >findById('last_name')->getValue()); assertEquals(FIRST_NAME_FB, $this->mink->getSession()->getPage()- >findById('first_name')->getValue()); assertEquals(MAIN_EMAIL, $this->mink->getSession()->getPage()->findById('email')- >getValue()); }
  • 31. な :Context /** * @When /^自分の住所情報を入 する。$/ */ public function inputMyAddress() { $this->mink->getSession()->getPage()->fillField('last_name', LAST_NAME_INPUT); $this->mink->getSession()->getPage()->fillField('first_name', FIRST_NAME_INPUT); $this->mink->getSession()->getPage()->fillField('last_name_kana', LAST_NAME_KANA); $this->mink->getSession()->getPage()->fillField('first_name_kana', FIRST_NAME_KANA); $this->mink->getSession()->getPage()->fillField('email', INPUT_EMAIL); $this->mink->getSession()->getPage()->fillField('zip3', ZIP3); $this->mink->getSession()->getPage()->fillField('zip4', ZIP4); $this->mink->getSession()->getPage()->selectFieldOption('prefecture', PREFECTURE); $this->mink->getSession()->getPage()->fillField('address', ADDRESS); $this->mink->getSession()->getPage()->fillField('address2', ADDRESS2); $this->mink->getSession()->getPage()->fillField('phone1', PHONE1); $this->mink->getSession()->getPage()->fillField('phone2', PHONE2); $this->mink->getSession()->getPage()->fillField('phone3', PHONE3); $this->mink->getSession()->getPage()->fillField('note', NOTE_SENDME); } /** * @Given /^確認ボタンを押下する。$/ */ public function pressSubmitShipmentButton() { $this->mink->getSession()->getPage()->clickLink('submit-shipment'); }
  • 32. な :Context /** * @Then /^確認画面に入 卣が勖単される。$/ */ public function assertDisplayInput() { $this->mink->assertSession()->pageTextContains(PRODUCT_NAME); $this->mink->assertSession()->pageTextContains(SHOP_NAME); $this->mink->assertSession()->pageTextContains(PRODUCT_PRICE); $this->mink->assertSession()->pageTextContains(PRODUCT_AND_WRAPPING_PRICE); $this->mink->assertSession()->pageTextContains(PRODUCT_ALL_PRICE); $this->mink->assertSession()->pageTextContains(LAST_NAME_INPUT . ' ' . FIRST_NAME_INPUT); $this->mink->assertSession()->pageTextContains(LAST_NAME_KANA . ' ' . FIRST_NAME_KANA); $this->mink->assertSession()->pageTextContains(INPUT_EMAIL); $this->mink->assertSession()->pageTextContains(ZIP3 . '-' . ZIP4); $this->mink->assertSession()->pageTextContains(PREFECTURE); $this->mink->assertSession()->pageTextContains(ADDRESS); $this->mink->assertSession()->pageTextContains(ADDRESS2); $this->mink->assertSession()->pageTextContains(PHONE1 . '-' . PHONE2 . '-' . PHONE3); $this->mink->assertSession()->pageTextContains(NOTE_SENDME); }
  • 33. な :Context /** * @When /^確定ボタンを押下する。$/ */ public function pressSubmitConfirm() { $this->mink->getSession()->getPage()->clickLink('submit-confirm'); } /** * @Then /^決済画面に遷移する。$/ */ public function assertConfirm2SBPS() { $this->mink->getSession()->wait(5000, 'typeof window.jQuery == "function"'); $this->mink->getSession()->wait(3000, 'window.document.getElementById("#title") > 0'); $this->mink->assertSession()->addressMatches("/¥/f01¥/FepBuyInfoReceive.do/"); } }
  • 35. まとめ • メリット – BDDで「なんちゃって」アジャイルを回避 – behatでテストファーストすることで事前の洗い出しが に • デメリット – スケジュールに追われる場合後回しになりがちで開発 プロセスを徹底するのが難しい – CIサーバに る定期 でアンドン化して 続メンテ ナンスしないと無効なテストケースが増殖
  • 36.