SlideShare une entreprise Scribd logo
1  sur  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

Contenu connexe

Tendances

ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門増田 亨
 
Prometheus at Preferred Networks
Prometheus at Preferred NetworksPrometheus at Preferred Networks
Prometheus at Preferred NetworksPreferred Networks
 
逆説のスタートアップ思考
逆説のスタートアップ思考逆説のスタートアップ思考
逆説のスタートアップ思考Takaaki Umada
 
ゲームのインフラをAwsで実戦tips全て見せます
ゲームのインフラをAwsで実戦tips全て見せますゲームのインフラをAwsで実戦tips全て見せます
ゲームのインフラをAwsで実戦tips全て見せますinfinite_loop
 
レガシー Web からの脱却 ~ 開発者が次に目指すべき Web アプリの姿とは?
レガシー Web からの脱却 ~ 開発者が次に目指すべき Web アプリの姿とは?レガシー Web からの脱却 ~ 開発者が次に目指すべき Web アプリの姿とは?
レガシー Web からの脱却 ~ 開発者が次に目指すべき Web アプリの姿とは?Akira Inoue
 
Dockerfileを改善するためのBest Practice 2019年版
Dockerfileを改善するためのBest Practice 2019年版Dockerfileを改善するためのBest Practice 2019年版
Dockerfileを改善するためのBest Practice 2019年版Masahito Zembutsu
 
Redmine にいろいろ埋め込んでみた
Redmine にいろいろ埋め込んでみたRedmine にいろいろ埋め込んでみた
Redmine にいろいろ埋め込んでみたKohei Nakamura
 
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021Hiroshi Tokumaru
 
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法Yoshifumi Kawai
 
ドメイン駆動設計 失敗したことと成功したこと
ドメイン駆動設計 失敗したことと成功したことドメイン駆動設計 失敗したことと成功したこと
ドメイン駆動設計 失敗したことと成功したことBIGLOBE Inc.
 
MySQLとPostgreSQLの基本的な実行プラン比較
MySQLとPostgreSQLの基本的な実行プラン比較MySQLとPostgreSQLの基本的な実行プラン比較
MySQLとPostgreSQLの基本的な実行プラン比較Shinya Sugiyama
 
Prometeusについてはじめてみよう / Let's start Prometeus
Prometeusについてはじめてみよう / Let's start PrometeusPrometeusについてはじめてみよう / Let's start Prometeus
Prometeusについてはじめてみよう / Let's start PrometeusTakeo Noda
 
ドキュメントシステムはこれを使え2015年版
ドキュメントシステムはこれを使え2015年版ドキュメントシステムはこれを使え2015年版
ドキュメントシステムはこれを使え2015年版Keiichiro Shikano
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話Koichiro Matsuoka
 
Base DDD(ドメイン駆動設計) 参考文献を巡る旅
Base DDD(ドメイン駆動設計) 参考文献を巡る旅Base DDD(ドメイン駆動設計) 参考文献を巡る旅
Base DDD(ドメイン駆動設計) 参考文献を巡る旅Takuya Kawabe
 
オブジェクト指向エクササイズのススメ
オブジェクト指向エクササイズのススメオブジェクト指向エクササイズのススメ
オブジェクト指向エクササイズのススメYoji Kanno
 
Micrometer/Prometheusによる大規模システムモニタリング #jsug #sf_26
Micrometer/Prometheusによる大規模システムモニタリング #jsug #sf_26Micrometer/Prometheusによる大規模システムモニタリング #jsug #sf_26
Micrometer/Prometheusによる大規模システムモニタリング #jsug #sf_26Yahoo!デベロッパーネットワーク
 
いまさら聞けないDocker - 第5回コンテナ型仮想化の情報交換会@大阪
いまさら聞けないDocker - 第5回コンテナ型仮想化の情報交換会@大阪いまさら聞けないDocker - 第5回コンテナ型仮想化の情報交換会@大阪
いまさら聞けないDocker - 第5回コンテナ型仮想化の情報交換会@大阪Kunihiro TANAKA
 

Tendances (20)

ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門
 
WebSocket / WebRTCの技術紹介
WebSocket / WebRTCの技術紹介WebSocket / WebRTCの技術紹介
WebSocket / WebRTCの技術紹介
 
Prometheus at Preferred Networks
Prometheus at Preferred NetworksPrometheus at Preferred Networks
Prometheus at Preferred Networks
 
逆説のスタートアップ思考
逆説のスタートアップ思考逆説のスタートアップ思考
逆説のスタートアップ思考
 
ゲームのインフラをAwsで実戦tips全て見せます
ゲームのインフラをAwsで実戦tips全て見せますゲームのインフラをAwsで実戦tips全て見せます
ゲームのインフラをAwsで実戦tips全て見せます
 
レガシー Web からの脱却 ~ 開発者が次に目指すべき Web アプリの姿とは?
レガシー Web からの脱却 ~ 開発者が次に目指すべき Web アプリの姿とは?レガシー Web からの脱却 ~ 開発者が次に目指すべき Web アプリの姿とは?
レガシー Web からの脱却 ~ 開発者が次に目指すべき Web アプリの姿とは?
 
Dockerfileを改善するためのBest Practice 2019年版
Dockerfileを改善するためのBest Practice 2019年版Dockerfileを改善するためのBest Practice 2019年版
Dockerfileを改善するためのBest Practice 2019年版
 
Redmine にいろいろ埋め込んでみた
Redmine にいろいろ埋め込んでみたRedmine にいろいろ埋め込んでみた
Redmine にいろいろ埋め込んでみた
 
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021
 
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
 
ドメイン駆動設計 失敗したことと成功したこと
ドメイン駆動設計 失敗したことと成功したことドメイン駆動設計 失敗したことと成功したこと
ドメイン駆動設計 失敗したことと成功したこと
 
MySQLとPostgreSQLの基本的な実行プラン比較
MySQLとPostgreSQLの基本的な実行プラン比較MySQLとPostgreSQLの基本的な実行プラン比較
MySQLとPostgreSQLの基本的な実行プラン比較
 
Prometeusについてはじめてみよう / Let's start Prometeus
Prometeusについてはじめてみよう / Let's start PrometeusPrometeusについてはじめてみよう / Let's start Prometeus
Prometeusについてはじめてみよう / Let's start Prometeus
 
ドキュメントシステムはこれを使え2015年版
ドキュメントシステムはこれを使え2015年版ドキュメントシステムはこれを使え2015年版
ドキュメントシステムはこれを使え2015年版
 
Maven基礎
Maven基礎Maven基礎
Maven基礎
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
 
Base DDD(ドメイン駆動設計) 参考文献を巡る旅
Base DDD(ドメイン駆動設計) 参考文献を巡る旅Base DDD(ドメイン駆動設計) 参考文献を巡る旅
Base DDD(ドメイン駆動設計) 参考文献を巡る旅
 
オブジェクト指向エクササイズのススメ
オブジェクト指向エクササイズのススメオブジェクト指向エクササイズのススメ
オブジェクト指向エクササイズのススメ
 
Micrometer/Prometheusによる大規模システムモニタリング #jsug #sf_26
Micrometer/Prometheusによる大規模システムモニタリング #jsug #sf_26Micrometer/Prometheusによる大規模システムモニタリング #jsug #sf_26
Micrometer/Prometheusによる大規模システムモニタリング #jsug #sf_26
 
いまさら聞けないDocker - 第5回コンテナ型仮想化の情報交換会@大阪
いまさら聞けないDocker - 第5回コンテナ型仮想化の情報交換会@大阪いまさら聞けないDocker - 第5回コンテナ型仮想化の情報交換会@大阪
いまさら聞けないDocker - 第5回コンテナ型仮想化の情報交換会@大阪
 

En vedette

Behatで行う、E2Eテスト入門
Behatで行う、E2Eテスト入門Behatで行う、E2Eテスト入門
Behatで行う、E2Eテスト入門leverages_event
 
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
 

En vedette (20)

Behatで行う、E2Eテスト入門
Behatで行う、E2Eテスト入門Behatで行う、E2Eテスト入門
Behatで行う、E2Eテスト入門
 
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
 

Similaire à 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
 

Similaire à 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の世界
 

Plus de 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
 

Plus de 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アプリ開発
 

Dernier

論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Gamesatsushi061452
 
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...Toru Tamaki
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイスCRI Japan, Inc.
 
Utilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native IntegrationsUtilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native IntegrationsWSO2
 
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NTT DATA Technology & Innovation
 
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Hiroshi Tomioka
 
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video UnderstandingToru Tamaki
 
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptxsn679259
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルCRI Japan, Inc.
 

Dernier (12)

論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
 
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
 
Utilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native IntegrationsUtilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native Integrations
 
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
 
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
 
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
 
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
 

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.