SlideShare ist ein Scribd-Unternehmen logo
1 von 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

Weitere ähnliche Inhalte

Was ist angesagt?

外部キー制約に伴うロックの小話
外部キー制約に伴うロックの小話外部キー制約に伴うロックの小話
外部キー制約に伴うロックの小話ichirin2501
 
徳丸本に載っていないWebアプリケーションセキュリティ
徳丸本に載っていないWebアプリケーションセキュリティ徳丸本に載っていないWebアプリケーションセキュリティ
徳丸本に載っていないWebアプリケーションセキュリティHiroshi Tokumaru
 
jooqってなんて読むの? から始めるO/RマッパーとSpringBootの世界
jooqってなんて読むの? から始めるO/RマッパーとSpringBootの世界jooqってなんて読むの? から始めるO/RマッパーとSpringBootの世界
jooqってなんて読むの? から始めるO/RマッパーとSpringBootの世界Y Watanabe
 
AndroidアプリのKotlin移行時に遭遇した問題と対処例
AndroidアプリのKotlin移行時に遭遇した問題と対処例AndroidアプリのKotlin移行時に遭遇した問題と対処例
AndroidアプリのKotlin移行時に遭遇した問題と対処例Kenichi Kambara
 
AWSでAPI Gatewayから非同期でLambdaを起動してS3にファイルアップロードしようとしたらハマった話。
AWSでAPI Gatewayから非同期でLambdaを起動してS3にファイルアップロードしようとしたらハマった話。AWSでAPI Gatewayから非同期でLambdaを起動してS3にファイルアップロードしようとしたらハマった話。
AWSでAPI Gatewayから非同期でLambdaを起動してS3にファイルアップロードしようとしたらハマった話。Takehiro Suemitsu
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)Takuto Wada
 
스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해beom kyun choi
 
Vue.js でタイマーを作る
Vue.js でタイマーを作るVue.js でタイマーを作る
Vue.js でタイマーを作るmizdra
 
第84回 雲勉【オンライン:初心者向け】ECS入門 _ CloudFront + ELB + ECS FargateでWebサイトを公開
第84回 雲勉【オンライン:初心者向け】ECS入門 _ CloudFront + ELB + ECS FargateでWebサイトを公開 第84回 雲勉【オンライン:初心者向け】ECS入門 _ CloudFront + ELB + ECS FargateでWebサイトを公開
第84回 雲勉【オンライン:初心者向け】ECS入門 _ CloudFront + ELB + ECS FargateでWebサイトを公開 Keisuke Matsuda
 
SORACOM UG 東京 #8 | eSIM オーバービュー
SORACOM UG 東京 #8 | eSIM オーバービューSORACOM UG 東京 #8 | eSIM オーバービュー
SORACOM UG 東京 #8 | eSIM オーバービューSORACOM,INC
 
ドメイン駆動設計 失敗したことと成功したこと
ドメイン駆動設計 失敗したことと成功したことドメイン駆動設計 失敗したことと成功したこと
ドメイン駆動設計 失敗したことと成功したことBIGLOBE Inc.
 
mongodb와 mysql의 CRUD 연산의 성능 비교
mongodb와 mysql의 CRUD 연산의 성능 비교mongodb와 mysql의 CRUD 연산의 성능 비교
mongodb와 mysql의 CRUD 연산의 성능 비교Woo Yeong Choi
 
Swaggerでのapi開発よもやま話
Swaggerでのapi開発よもやま話Swaggerでのapi開発よもやま話
Swaggerでのapi開発よもやま話KEISUKE KONISHI
 
ドメインオブジェクトの見つけ方・作り方・育て方
ドメインオブジェクトの見つけ方・作り方・育て方ドメインオブジェクトの見つけ方・作り方・育て方
ドメインオブジェクトの見つけ方・作り方・育て方増田 亨
 
文字コードに起因する脆弱性とその対策(増補版)
文字コードに起因する脆弱性とその対策(増補版)文字コードに起因する脆弱性とその対策(増補版)
文字コードに起因する脆弱性とその対策(増補版)Hiroshi Tokumaru
 
MySQLとPostgreSQLの基本的なバックアップ比較
MySQLとPostgreSQLの基本的なバックアップ比較MySQLとPostgreSQLの基本的なバックアップ比較
MySQLとPostgreSQLの基本的なバックアップ比較Shinya Sugiyama
 
Presto ベースのマネージドサービス Amazon Athena
Presto ベースのマネージドサービス Amazon AthenaPresto ベースのマネージドサービス Amazon Athena
Presto ベースのマネージドサービス Amazon AthenaAmazon Web Services Japan
 
Chrome拡張機能の作りかた
Chrome拡張機能の作りかたChrome拡張機能の作りかた
Chrome拡張機能の作りかたaozou99
 

Was ist angesagt? (20)

Java8でRDBMS作ったよ
Java8でRDBMS作ったよJava8でRDBMS作ったよ
Java8でRDBMS作ったよ
 
外部キー制約に伴うロックの小話
外部キー制約に伴うロックの小話外部キー制約に伴うロックの小話
外部キー制約に伴うロックの小話
 
徳丸本に載っていないWebアプリケーションセキュリティ
徳丸本に載っていないWebアプリケーションセキュリティ徳丸本に載っていないWebアプリケーションセキュリティ
徳丸本に載っていないWebアプリケーションセキュリティ
 
jooqってなんて読むの? から始めるO/RマッパーとSpringBootの世界
jooqってなんて読むの? から始めるO/RマッパーとSpringBootの世界jooqってなんて読むの? から始めるO/RマッパーとSpringBootの世界
jooqってなんて読むの? から始めるO/RマッパーとSpringBootの世界
 
AndroidアプリのKotlin移行時に遭遇した問題と対処例
AndroidアプリのKotlin移行時に遭遇した問題と対処例AndroidアプリのKotlin移行時に遭遇した問題と対処例
AndroidアプリのKotlin移行時に遭遇した問題と対処例
 
AWSでAPI Gatewayから非同期でLambdaを起動してS3にファイルアップロードしようとしたらハマった話。
AWSでAPI Gatewayから非同期でLambdaを起動してS3にファイルアップロードしようとしたらハマった話。AWSでAPI Gatewayから非同期でLambdaを起動してS3にファイルアップロードしようとしたらハマった話。
AWSでAPI Gatewayから非同期でLambdaを起動してS3にファイルアップロードしようとしたらハマった話。
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
 
스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해
 
Vue.js でタイマーを作る
Vue.js でタイマーを作るVue.js でタイマーを作る
Vue.js でタイマーを作る
 
第84回 雲勉【オンライン:初心者向け】ECS入門 _ CloudFront + ELB + ECS FargateでWebサイトを公開
第84回 雲勉【オンライン:初心者向け】ECS入門 _ CloudFront + ELB + ECS FargateでWebサイトを公開 第84回 雲勉【オンライン:初心者向け】ECS入門 _ CloudFront + ELB + ECS FargateでWebサイトを公開
第84回 雲勉【オンライン:初心者向け】ECS入門 _ CloudFront + ELB + ECS FargateでWebサイトを公開
 
SORACOM UG 東京 #8 | eSIM オーバービュー
SORACOM UG 東京 #8 | eSIM オーバービューSORACOM UG 東京 #8 | eSIM オーバービュー
SORACOM UG 東京 #8 | eSIM オーバービュー
 
ドメイン駆動設計 失敗したことと成功したこと
ドメイン駆動設計 失敗したことと成功したことドメイン駆動設計 失敗したことと成功したこと
ドメイン駆動設計 失敗したことと成功したこと
 
mongodb와 mysql의 CRUD 연산의 성능 비교
mongodb와 mysql의 CRUD 연산의 성능 비교mongodb와 mysql의 CRUD 연산의 성능 비교
mongodb와 mysql의 CRUD 연산의 성능 비교
 
Swaggerでのapi開発よもやま話
Swaggerでのapi開発よもやま話Swaggerでのapi開発よもやま話
Swaggerでのapi開発よもやま話
 
ドメインオブジェクトの見つけ方・作り方・育て方
ドメインオブジェクトの見つけ方・作り方・育て方ドメインオブジェクトの見つけ方・作り方・育て方
ドメインオブジェクトの見つけ方・作り方・育て方
 
文字コードに起因する脆弱性とその対策(増補版)
文字コードに起因する脆弱性とその対策(増補版)文字コードに起因する脆弱性とその対策(増補版)
文字コードに起因する脆弱性とその対策(増補版)
 
MySQLとPostgreSQLの基本的なバックアップ比較
MySQLとPostgreSQLの基本的なバックアップ比較MySQLとPostgreSQLの基本的なバックアップ比較
MySQLとPostgreSQLの基本的なバックアップ比較
 
Amazon VPCトレーニング-VPCの説明
Amazon VPCトレーニング-VPCの説明Amazon VPCトレーニング-VPCの説明
Amazon VPCトレーニング-VPCの説明
 
Presto ベースのマネージドサービス Amazon Athena
Presto ベースのマネージドサービス Amazon AthenaPresto ベースのマネージドサービス Amazon Athena
Presto ベースのマネージドサービス Amazon Athena
 
Chrome拡張機能の作りかた
Chrome拡張機能の作りかたChrome拡張機能の作りかた
Chrome拡張機能の作りかた
 

Andere mochten auch

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
 

Andere mochten auch (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
 

Ähnlich wie 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
 

Ähnlich wie 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の世界
 

Mehr von 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
 

Mehr von 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アプリ開発
 

Kürzlich hochgeladen

Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Hiroshi Tomioka
 
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NTT DATA Technology & Innovation
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルCRI Japan, Inc.
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)Hiroshi Tomioka
 
論文紹介: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 を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイスCRI Japan, Inc.
 
論文紹介: 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
 
論文紹介: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
 

Kürzlich hochgeladen (11)

Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
 
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。
 
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
 
論文紹介: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 を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
 
論文紹介: 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
 
論文紹介: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
 

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.