$30 off During Our Annual Pro Sale. View Details »

PageObjectPattern使うのやめた話

 PageObjectPattern使うのやめた話

2019/4/19 Selenium Conf Tokyo 2019 Lightning Talk

tsuemura

April 19, 2019
Tweet

More Decks by tsuemura

Other Decks in Technology

Transcript

  1. Page Object Pattern 使うのやめた話 Page Object Pattern 使うのやめた話 Page Object

    Pattern 使うのやめた話 Page Object Pattern 使うのやめた話 Page Object Pattern 使うのやめた話 Page Object Pattern 使うのやめた話 末村 拓也 @ 株式会社オープンロジ 末村 拓也 @ 株式会社オープンロジ 末村 拓也 @ 株式会社オープンロジ 末村 拓也 @ 株式会社オープンロジ 末村 拓也 @ 株式会社オープンロジ 末村 拓也 @ 株式会社オープンロジ Takuya Suemura @ OPENLOGI Inc. Takuya Suemura @ OPENLOGI Inc. Takuya Suemura @ OPENLOGI Inc. Takuya Suemura @ OPENLOGI Inc. Takuya Suemura @ OPENLOGI Inc. Takuya Suemura @ OPENLOGI Inc.
  2. 自己紹介 自己紹介 自己紹介 自己紹介 自己紹介 自己紹介 末村 拓也 (Takuya Suemura)

    末村 拓也 (Takuya Suemura) 末村 拓也 (Takuya Suemura) 末村 拓也 (Takuya Suemura) 末村 拓也 (Takuya Suemura) 末村 拓也 (Takuya Suemura) 物流スタートアップ『OPENLOGI 』のQA エンジニアです 物流スタートアップ『OPENLOGI 』のQA エンジニアです 物流スタートアップ『OPENLOGI 』のQA エンジニアです 物流スタートアップ『OPENLOGI 』のQA エンジニアです 物流スタートアップ『OPENLOGI 』のQA エンジニアです 物流スタートアップ『OPENLOGI 』のQA エンジニアです 日本の皆さんには↓の記事が名刺代わりになるでしょうか 日本の皆さんには↓の記事が名刺代わりになるでしょうか 日本の皆さんには↓の記事が名刺代わりになるでしょうか 日本の皆さんには↓の記事が名刺代わりになるでしょうか 日本の皆さんには↓の記事が名刺代わりになるでしょうか 日本の皆さんには↓の記事が名刺代わりになるでしょうか                  
  3. 今日は、ロケーターの 今日は、ロケーターの 今日は、ロケーターの 今日は、ロケーターの 今日は、ロケーターの 今日は、ロケーターの メンテナンス性の話を メンテナンス性の話を メンテナンス性の話を メンテナンス性の話を

    メンテナンス性の話を メンテナンス性の話を したいとおもいます。 したいとおもいます。 したいとおもいます。 したいとおもいます。 したいとおもいます。 したいとおもいます。
  4. スライドに出てくるサンプルコードは スライドに出てくるサンプルコードは スライドに出てくるサンプルコードは スライドに出てくるサンプルコードは スライドに出てくるサンプルコードは スライドに出てくるサンプルコードは CodeceptJS で書かれています CodeceptJS で書かれています

    CodeceptJS で書かれています CodeceptJS で書かれています CodeceptJS で書かれています CodeceptJS で書かれています https://codecept.io https://codecept.io https://codecept.io https://codecept.io https://codecept.io https://codecept.io ( なるべくフレームワーク特有の機能は使わず説明します) ( なるべくフレームワーク特有の機能は使わず説明します) ( なるべくフレームワーク特有の機能は使わず説明します) ( なるべくフレームワーク特有の機能は使わず説明します) ( なるべくフレームワーク特有の機能は使わず説明します) ( なるべくフレームワーク特有の機能は使わず説明します)
  5. Page Object Pattern Page Object Pattern Page Object Pattern Page

    Object Pattern Page Object Pattern Page Object Pattern 使っていますか? 使っていますか? 使っていますか? 使っていますか? 使っていますか? 使っていますか?
  6. Page Object Pattern を Page Object Pattern を Page Object

    Pattern を Page Object Pattern を Page Object Pattern を Page Object Pattern を 知らない人? 知らない人? 知らない人? 知らない人? 知らない人? 知らない人?
  7. 一応解説: Page Object とは 一応解説: Page Object とは 一応解説: Page

    Object とは 一応解説: Page Object とは 一応解説: Page Object とは 一応解説: Page Object とは ページの要素セレクタや操作手順をまとめたオブジェクト ページの要素セレクタや操作手順をまとめたオブジェクト ページの要素セレクタや操作手順をまとめたオブジェクト ページの要素セレクタや操作手順をまとめたオブジェクト ページの要素セレクタや操作手順をまとめたオブジェクト ページの要素セレクタや操作手順をまとめたオブジェクト const const page page = = { { nameField nameField: : locate locate( ('input#name' 'input#name') ), , sendButton sendButton: : locate locate( ('button[type=submit]' 'button[type=submit]') ), , register register: : ( (name name) ) => => { { I I. .fillField fillField( (this this. .nameField nameField, , name name) ) I I. .click click( (this this. .sendButton sendButton) ) } } } } page page. .register register( ('Takuya Suemura' 'Takuya Suemura') )
  8. Page Object を使うメリット Page Object を使うメリット Page Object を使うメリット Page

    Object を使うメリット Page Object を使うメリット Page Object を使うメリット 要素や操作が抽象化されるので 要素や操作が抽象化されるので 要素や操作が抽象化されるので 要素や操作が抽象化されるので 要素や操作が抽象化されるので 要素や操作が抽象化されるので コードが読みやすくなる コードが読みやすくなる コードが読みやすくなる コードが読みやすくなる コードが読みやすくなる コードが読みやすくなる 同じ操作を繰り返し利用できる 同じ操作を繰り返し利用できる 同じ操作を繰り返し利用できる 同じ操作を繰り返し利用できる 同じ操作を繰り返し利用できる 同じ操作を繰り返し利用できる デザインの変更に強くなる デザインの変更に強くなる デザインの変更に強くなる デザインの変更に強くなる デザインの変更に強くなる デザインの変更に強くなる                  
  9. ページ数が少ないころはよかった ページ数が少ないころはよかった ページ数が少ないころはよかった ページ数が少ないころはよかった ページ数が少ないころはよかった ページ数が少ないころはよかった

  10. ページが9999 枚になったら? ページが9999 枚になったら? ページが9999 枚になったら? ページが9999 枚になったら? ページが9999 枚になったら?

    ページが9999 枚になったら?
  11. PageObject も9999 個作る????? PageObject も9999 個作る????? PageObject も9999 個作る????? PageObject

    も9999 個作る????? PageObject も9999 個作る????? PageObject も9999 個作る????? const const page0001 page0001 = = { {... ...} } const const page0002 page0002 = = { {... ...} } const const page0003 page0003 = = { {... ...} } const const page0004 page0004 = = { {... ...} } const const page0005 page0005 = = { {... ...} } const const page0006 page0006 = = { {... ...} } const const page0007 page0007 = = { {... ...} } const const page0008 page0008 = = { {... ...} } const const page0009 page0009 = = { {... ...} } const const page0010 page0010 = = { {... ...} } const const page0011 page0011 = = { {... ...} } const const page0012 page0012 = = { {... ...} }
  12. 9999 行のimport 文を書く?????? 9999 行のimport 文を書く?????? 9999 行のimport 文を書く?????? 9999

    行のimport 文を書く?????? 9999 行のimport 文を書く?????? 9999 行のimport 文を書く?????? import import Page0001 Page0001 from from './page0001' './page0001' import import Page0002 Page0002 from from './page0002' './page0002' import import Page0003 Page0003 from from './page0003' './page0003' import import Page0004 Page0004 from from './page0004' './page0004' import import Page0005 Page0005 from from './page0005' './page0005' import import Page0006 Page0006 from from './page0006' './page0006' import import Page0007 Page0007 from from './page0007' './page0007' import import Page0008 Page0008 from from './page0008' './page0008' import import Page0009 Page0009 from from './page0009' './page0009' import import Page0010 Page0010 from from './page0010' './page0010' import import Page0011 Page0011 from from './page0011' './page0011' import import Page0012 Page0012 from from './page0012' './page0012' import import Page0013 Page0013 from from './page0013' './page0013'
  13. PageObjectPattern の弱点: PageObjectPattern の弱点: PageObjectPattern の弱点: PageObjectPattern の弱点: PageObjectPattern の弱点:

    PageObjectPattern の弱点: メンテナンスコストが線形に増大する メンテナンスコストが線形に増大する メンテナンスコストが線形に増大する メンテナンスコストが線形に増大する メンテナンスコストが線形に増大する メンテナンスコストが線形に増大する ※このグラフはただのイメージです ※このグラフはただのイメージです ※このグラフはただのイメージです ※このグラフはただのイメージです ※このグラフはただのイメージです ※このグラフはただのイメージです
  14. どうやって解決したか どうやって解決したか どうやって解決したか どうやって解決したか どうやって解決したか どうやって解決したか 14 / 23

  15. Page Object Page Object Page Object Page Object Page Object

    Page Object やめました やめました やめました やめました やめました やめました 15 / 23
  16. 代わりに 代わりに 代わりに 代わりに 代わりに 代わりに コンポーネントの抽象化 コンポーネントの抽象化 コンポーネントの抽象化 コンポーネントの抽象化

    コンポーネントの抽象化 コンポーネントの抽象化 16 / 23
  17. ページの数が爆発的に増えたからといって ページの数が爆発的に増えたからといって ページの数が爆発的に増えたからといって ページの数が爆発的に増えたからといって ページの数が爆発的に増えたからといって ページの数が爆発的に増えたからといって コンポーネントの種類も爆発的に増えるわけではない コンポーネントの種類も爆発的に増えるわけではない コンポーネントの種類も爆発的に増えるわけではない コンポーネントの種類も爆発的に増えるわけではない

    コンポーネントの種類も爆発的に増えるわけではない コンポーネントの種類も爆発的に増えるわけではない コンポーネント = ページを構成する部品 コンポーネント = ページを構成する部品 コンポーネント = ページを構成する部品 コンポーネント = ページを構成する部品 コンポーネント = ページを構成する部品 コンポーネント = ページを構成する部品
  18. コンポーネントを抽象化した コンポーネントを抽象化した コンポーネントを抽象化した コンポーネントを抽象化した コンポーネントを抽象化した コンポーネントを抽象化した 要素そのもののセレクタを定義するのではなく、 要素そのもののセレクタを定義するのではなく、 要素そのもののセレクタを定義するのではなく、 要素そのもののセレクタを定義するのではなく、

    要素そのもののセレクタを定義するのではなく、 要素そのもののセレクタを定義するのではなく、 セレクタを返す関数を定義する セレクタを返す関数を定義する セレクタを返す関数を定義する セレクタを返す関数を定義する セレクタを返す関数を定義する セレクタを返す関数を定義する const const button button = = label label => => locate locate( (`button= `button=${ ${label label} }` `) ) // 'Submit' というテキストを持つボタンをクリックする // 'Submit' というテキストを持つボタンをクリックする I I. .click click( (button button( ('Submit' 'Submit') )) )
  19. コンポーネントを抽象化した コンポーネントを抽象化した コンポーネントを抽象化した コンポーネントを抽象化した コンポーネントを抽象化した コンポーネントを抽象化した たとえばBootstrap の入力フォーム たとえばBootstrap の入力フォーム

    たとえばBootstrap の入力フォーム たとえばBootstrap の入力フォーム たとえばBootstrap の入力フォーム たとえばBootstrap の入力フォーム < <div div class class= =" "form-group form-group" "> > < <label label> >Email address Email address</ </label label> > < <input input type type= =" "email email" " class class= =" "form-control form-control" " placeholder placeholder= =" "Enter email Enter email" "> > </ </div div> >
  20. コンポーネントを抽象化した コンポーネントを抽象化した コンポーネントを抽象化した コンポーネントを抽象化した コンポーネントを抽象化した コンポーネントを抽象化した label を引数に取り、対応するinput を返す関数を定義した label

    を引数に取り、対応するinput を返す関数を定義した label を引数に取り、対応するinput を返す関数を定義した label を引数に取り、対応するinput を返す関数を定義した label を引数に取り、対応するinput を返す関数を定義した label を引数に取り、対応するinput を返す関数を定義した const const field field = = label label => => { { return return locate locate( ('div.form-group' 'div.form-group') ) // <div class="form-group"> // <div class="form-group"> . .withText withText( (label label) ) // label に指定したテキストを持つ // label に指定したテキストを持つ . .find find( ('input' 'input') ) // input 要素を選択 // input 要素を選択 } } I I. .fillField fillField( (field field( ('Email address' 'Email address') ), , 'foo@example.com' 'foo@example.com') ) 同じコンポーネントを使っていれば汎用的に使いまわせる 同じコンポーネントを使っていれば汎用的に使いまわせる 同じコンポーネントを使っていれば汎用的に使いまわせる 同じコンポーネントを使っていれば汎用的に使いまわせる 同じコンポーネントを使っていれば汎用的に使いまわせる 同じコンポーネントを使っていれば汎用的に使いまわせる
  21. 9999 個のPageObject を作るのではなく 9999 個のPageObject を作るのではなく 9999 個のPageObject を作るのではなく 9999

    個のPageObject を作るのではなく 9999 個のPageObject を作るのではなく 9999 個のPageObject を作るのではなく // Don't do this // Don't do this const const page0001 page0001 = = { {... ...} } const const page0002 page0002 = = { {... ...} } const const page0003 page0003 = = { {... ...} } const const page0004 page0004 = = { {... ...} } const const page0005 page0005 = = { {... ...} } const const page0006 page0006 = = { {... ...} } const const page0007 page0007 = = { {... ...} } const const page0008 page0008 = = { {... ...} } const const page0009 page0009 = = { {... ...} } const const page0010 page0010 = = { {... ...} } const const page0011 page0011 = = { {... ...} }
  22. コンポーネントを抽象化したロケータを コンポーネントを抽象化したロケータを コンポーネントを抽象化したロケータを コンポーネントを抽象化したロケータを コンポーネントを抽象化したロケータを コンポーネントを抽象化したロケータを 一つ作りましょう 一つ作りましょう 一つ作りましょう 一つ作りましょう

    一つ作りましょう 一つ作りましょう Bootstrap, Vuetify, AdminLTE, ...etc Bootstrap, Vuetify, AdminLTE, ...etc Bootstrap, Vuetify, AdminLTE, ...etc Bootstrap, Vuetify, AdminLTE, ...etc Bootstrap, Vuetify, AdminLTE, ...etc Bootstrap, Vuetify, AdminLTE, ...etc const const bootstrapComponents bootstrapComponents = = { { button button: : label label => => locate locate( ('button' 'button') ). .withText withText( (button button) ), , field field: : label label => => locate locate( ('div.form-group' 'div.form-group') ). .withText withText( (label label) ) . .find find( ('input' 'input') ), , // and something // and something } } I I. .click click( (bootstrapComponents bootstrapComponents. .button button( ('Thank you for Listening!' 'Thank you for Listening!') )) )
  23. ご清聴ありがとうございました ご清聴ありがとうございました ご清聴ありがとうございました ご清聴ありがとうございました ご清聴ありがとうございました ご清聴ありがとうございました Thank you for listening!

    Thank you for listening! Thank you for listening! Thank you for listening! Thank you for listening! Thank you for listening!