Your SlideShare is downloading. ×
behatで始めるBDD
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

behatで始めるBDD

3,089
views

Published on

第65回 PHP勉強会@東京 …

第65回 PHP勉強会@東京
http://atnd.org/events/36965

での発表資料

Published in: Technology

0 Comments
8 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
3,089
On Slideshare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
0
Comments
0
Likes
8
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. 第65回 PHP勉強会 @東京(Engine Yard)behat/PHPUnitで始める BDD/TDD2013/02/28(木) @ビルコム
  • 2. 前置き。
  • 3. about tchikuba• 所属 – ビルコム株式会社• 自社サービス – ReBuy http://rebuy.jp/ – Okkru https://okkru.jp• 役割 – 開発Playing Manager• いいね! – Linux、ビール、宇宙平和• facebook/twitter – tchikuba
  • 4. ReBuy:facebookコマースアプリ
  • 5. Okkru:ソーシャルギフト
  • 6. 我々の諸環境• OS:CentOS(nifty cloud)• Webサーバ:Nginx/Apache• DBサーバ:MySQL• CIサーバ:Jenkins/SeleniumServer• 言語:PHP• フレームワーク:Zendframework• フロント:jQuery(Mobile)• SCM:Git• BTS:Backlog
  • 7. 聞きたいこと。•開発プロセス?•BDD/TDD?
  • 8. 本題。
  • 9. TDDとは• Test-Driven Developmentの• 和訳:テスト駆動開発• 特徴 – テストファースト – リファクタリング• メリット – スパゲッティの塩分低下 – 開発アジリティ上昇
  • 10. BDDとは• Behavior-Driven Developmentの• 和訳:振舞駆動開発• 特徴 – 自然言語 – 要求仕様(スペック)• メリット – け れ 厙 – オブジェクト指向強化
  • 11. BDD/TDDのフレームワーク • BDD – behat + mink – PHPSpec – Selenium • TDD – PHPUnit
  • 12. PHPUnit。
  • 13. behat。
  • 14. behat環境設定• インストール (PHP5.3.4 ≧推奨) – Composer • vi composer.json • curl http://getcomposer.org/installer | php • php composer.phar install – PHAR – Git• 初期プロジェクト生成 – behat --init
  • 15. ディレクトリ構成• behat_root/ – features/ • bootstrap/ – FeatureContext.php • *.feature – behat.yml – build.xml *for Jenkins• *.feature:機能+シナリオ(複数可)• FeatureContext.php:テスト定義• bootstrap配下はオートロードされる
  • 16. く却 コマンド• テスト – behat [features/*.feature]• コンテキスト一覧 – behat –dl• スニペット生成 – behat –f snippets
  • 17. 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.
  • 18. Contextの<?phpuse 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; }(続く)
  • 19. 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); }(続く)
  • 20. 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()); }}(終わり)
  • 21. FeatureContextの<?phpuse 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;
  • 22. 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)); }}
  • 23. り な :featureFeature: sendme 商品を自分で受け取ることが出来る。 @javascript Scenario: 商品を自分贈りで購入する。 Given テスト用商品ページにアクセスする。 When 購入ボタンを押下する。 Then ログイン画面に遷移する。 When ログインボタンを押下する。 Then facebookログインページに遷移する。 When facebookログインする。 Then 友人選択画面に遷移する。 When 友人選択画面で自分贈りを選択する。 Then 自分の住所情報が入 出来る。 And FBから引いた情報が補完されている。 When 自分の住所情報を入 する。 And 確認ボタンを押下する。 Then 確認画面に入 卣が勖単される。 When 確定ボタンを押下する。 Then 決済画面に遷移する。
  • 24. り な :Context<?phpuse 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; }(続く)
  • 25. り な :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); }
  • 26. り な :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); }
  • 27. り な :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(); }
  • 28. り な :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); }
  • 29. り な :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()); }
  • 30. り な :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); }
  • 31. り な :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); }
  • 32. り な :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/"); }}
  • 33. でも。
  • 34. まとめ• メリット – BDDで「なんちゃって」アジャイルを回避 – behatでテストファーストすることで事前の洗い出しが に• デメリット – スケジュールに追われる場合後回しになりがちで開発 プロセスを徹底するのが難しい – CIサーバに る定期 でアンドン化して 続メンテ ナンスしないと無効なテストケースが増殖
  • 35. \(^o^)/オワタ facebook/twitterアカウント:tchikuba

×