最小のCodeception + Gherkin + PageObjectによる自動化







Codeceptionの Page Objectデザインパターンを使用したガーキンの実装の具体例をインターネット上で見つけられなかったので、このパターンの独自の実装についてインターネットに伝えるのは場違いではないと思いました。



この記事は、Codeceptionまたは類似のフレームワークにすでに少し慣れているが、テストオブジェクトを使用してテストを読みやすくしたり、サポートを簡素化し、余分なコードの量を減らしたりする方法をまだ知らない人を対象としています。 それでも、自動化プロジェクトをゼロから組み立てるすべての主要なポイントをステップごとに説明しようとしました。



Page Objectテンプレートを使用すると、ページ要素を使用して作業をカプセル化できます。これにより、コードの量を減らし、サポートを簡素化できます。 UIのすべての変更は簡単かつ迅速に実装されます。このページを説明するPage Objectクラスを更新するだけです。 このアーキテクチャアプローチのもう1つの重要な利点は、HTMLテストスクリプトを詳細で混乱させないことです。これにより、理解しやすく、読みやすくなります。



これは、ページオブジェクトを使用しないテストの外観です。







ページオブジェクトの使用







基本環境のインストールについては説明しません。初期データを提供します。





テストを実行するには、次も必要です。





Codeceptionを展開



Codeceptionのインストールに進みます。



ターミナルで必要なディレクトリを開き、プロジェクトを収集するか、プロジェクトのディレクトリを作成してそこに移動します。



mkdir ProjectTutorial cd ProjectTutorial
      
      





Codeceptionフレームワークとその依存関係をインストールします。



 composer require codeception/codeception --dev
      
      









プロジェクトのcomposer.json依存関係インストールファイルは次のようになります。



 { "require": { "php": ">=5.6.0 <8.0", "facebook/webdriver": ">=1.1.3 <2.0", "behat/gherkin": "^4.4.0", "codeception/phpunit-wrapper": "^6.0.9|^7.0.6" }, "require-dev": { "codeception/codeception": "^2.5", "codeception/base": "^2.5" } }
      
      





プロジェクトを展開します。



 php vendor/bin/codecept bootstrap
      
      









プロジェクトのインストール方法の詳細については、 公式ドキュメントを参照してください



この段階で、プロジェクトに3セットのテストが作成されます。 デフォルトでは、Codeceptionはそれらを受け入れ、機能、およびユニットに分割します。 これらのセットに対して、Codeceptionは3つのymlファイルも生成します。 それらに必要なすべての構成を示し、モジュールとプロパティを接続してテストを実行します。



このレッスンはAcceptanceテストの例に基づいているため、Acceptance.suite.ymlで設定を行います。



PHP Storm(または別のお気に入りの開発環境)でプロジェクトを開き、 Acceptance.suite.ymlに移動します(デフォルトでは、tests / acceptance.suite.ymlフォルダーにあります)。

最低限必要な依存関係を書き留め、常にフォーマットに注意を払います。 モジュールは「-」記号で区切られ、同じレベルである必要があります。そうでない場合、テストの開始時にエラーが発生します。



判明した:



 actor: AcceptanceTester modules: enabled: - WebDriver: url: 'http://yandex.ru/' //    ,        browser: 'chrome' - \Helper\Acceptance //          gherkin: contexts: default: - AcceptanceTester
      
      





そして、いくつかの準備作業:



プロジェクトルートに別のディレクトリを作成します(私はlibを持っています)。

このディレクトリで、実行ファイルrun.shを作成します。これにより、SeleniumとChromeドライバーが実行されます。



ここにSeleniumとChromeドライバーを配置し、run.shにrunコマンドを記述します。



 java -jar -Dwebdriver.chrome.driver=chromedriver_241 selenium-server-standalone-3.14.0.jar
      
      





プロジェクトでの表示:







コンソールに戻り、アクセス権を変更します。



 chmod +x ./run.sh
      
      





(注。ディレクトリにあるドライバーの名前は、startコマンドで指定された名前と正確に一致する必要があります)。



これに戻らないように、今すぐSeleniumとWebdriverを起動できます。 これを行うには、新しいターミナルタブを開き、run.shファイルがあるディレクトリに移動して、起動コマンドを記述します。



 ~/AutomationProjects/ProjectTutorial/lib$ ./run.sh
      
      





サーバーが実行されていることを確認します。







実行状態のままにします。 これで準備作業は完了です。



テストスクリプトを書く



テストケースの機能ファイルの作成に進みます。 これを行うには、特別なコマンドがCodeceptionで提供され、コンソールで実行します:



 cept g:feature acceptance check
      
      





(「チェック」に注意してください-私のテストの名前)



受け入れフォルダーに新しいcheck.featureファイルが表示されます。







デフォルトのコンテンツは必要ありません。すぐに削除してテストを作成します。



コレクターがキリル文字を認識するために、#language:ruでスクリプトを開始することを忘れないでください。

ロシア語で短いスクリプトを書いています。 各文は「When」、「Then」、「And」、記号「*」などのキーワードで始まる必要があることを思い出してください。



私の例では、YandexのWebサイトを取り上げましたが、どれでもかまいません。







テストに含まれるステップを確認するために、ターミナルでスクリプトを実行します。



 cept dry-run acceptance check.feature
      
      









スクリプトのステップはコンソールに表示されますが、それらの実装はまだ利用できません。



次に、メソッドを実装するためのテンプレートを自動的に生成するコマンドを実行します。



 cept gherkin:snippets acceptance
      
      









スクリプトから引用符で囲まれた名前はすべて、変数argに置き換えられます。

それらをターミナルからコピーし、 AcceptanceTester.phpファイルに貼り付けます。ここには、ページ要素を操作するためのメソッドがあります。







メソッドの名前を読みやすく、その本質を反映して(必ずしもそうではありません)、実装を記述します。







すべてがシンプルですが、ライブラリの必要なコマンドを要求するStormなどのスマートな開発環境で作業している場合はさらに簡単です。







余分な部分を削除してメソッドを記述します。



 /** * @When      */ public function step_beingOnMainPage($page) { $this->amOnPage('/'); } /** * @Then    :element */ public function step_seeElement($element) { this->seeElement($element); } /** * @Then    :button */ public function step_clickOnButton($button) { $this->click($button); } /** * @Then    :field  :text */ public function step_fillField($field, $text) { $this->fillField($field, $text); }
      
      





何が起こったのか見てみましょう。 現在、実装されているメソッド(ステップ)を示すチームを立ち上げます。



 cept gherkin:steps acceptance
      
      









成功!



ただし、機能ファイルの手順はまだメソッドとして認識されません。







Stormがステップの処理方法を理解するために、名前空間Gherkin ContextからContextインターフェースを実装するトリックを行います。



 namespace Behat\Behat\Context { interface Context {} }
      
      





AcceptanceTesterクラスを名前空間でラップし、Contextから継承します



 implements \Behat\Behat\Context\Context
      
      









これで、機能ファイルのすべての手順が実装に関連付けられました。







Webdriverが何をクリックし、どこを見るべきかを理解するには、要素の読み取り可能な名前とページアドレスを、引数としてメソッドに分類される対応するロケーターとURLに置き換える必要があります。



次に、フォームのテストを取得します。







そして、あなたは実行することができます:



 cept run acceptance
      
      









合格



ページ要素のロードに時間がかかる場合は、目的のメソッドに待機を追加できます。



 $this->waitForElementVisible($element);
      
      





テストケースに戻ります。 要素とページの明確な名前の代わりに、HTML要素とURLが表示されるという事実により、テストの読みやすさがすべて失われていることに動揺しています。



これを修正したい場合は、Page Objectパターンの実装に移りましょう。



ページオブジェクトに移動



_supportディレクトリで、クラスページを配置するPageディレクトリを作成します。



 php vendor/bin/codecept generate:pageobject MainPage
      
      





最初のページオブジェクトはYandexのメインページです。MainPageと呼びましょう。同じクラスを呼び出します。







ここでは、オブジェクトを作成せずに呼び出せるように、静的フィールドとメソッドを宣言します。



Acceptance.suite.ymlの構成では、開始ページurl: yandex.ruをすでに示しているため、メインページには指定するだけで十分です。



 public static $URL = '/';
      
      





次はページ要素の配列です。 複数の要素のロケーターについて説明し、明確で一意の名前を付けます。



次に、getElementメソッドを追加する必要があります。このメソッドは、配列の要素の名前でロケーターを返します。



その結果、次のことができます。



 <?php //location: tests/_support/Page/MainPage.php namespace Page; /**   */ class MainPage { public static $URL = '/'; public static $elements = array( ' ' => "//*[@id='wd-wrapper-_afisha']", ' ' => "//*[@data-statlog='afisha.title.link']", ' ' => "//*[@class='weather__icon weather__icon_ovc']|//*[@class='weather__icon weather__icon_skc_d']", ); public static function getElement($name){ return self::$elements[$name]; } }
      
      





いくつかのページクラスを追加します。



/ **ポスター* /







/ **ポスター-検索結果* /







AcceptanceTester.phpクラスに戻り、メソッドを作成しました。

その中にPageObjectクラスから配列を作成します。ここで、ページに名前を割り当て、名前空間でクラス名を示します。



  private $pages = array( " " => "\Page\MainPage", "" => "\Page\AfishaPage", " -  " => "\Page\AfishaResult" );
      
      





同様に、新しいPageObjectがこの配列に追加されます。



次に、現在のページのPageObjectへのリンクを保存するcurrentPageフィールドを作成する必要があります。



 private $currentPage;
      
      





メソッドを作成し、呼び出されたときにcurrentPageを取得して、必要なPageObjectクラスを初期化できます。



「ユーザーがページのページ名ページに移動したとき」という方法を使用して、このようなステップを作成することは論理的です。 次に、チェックなしでPageObjectクラスを初期化する最も簡単な方法は次のようになります。



 /** * @When     :page */ public function step_beingOn($page) { //   pageObject $this->currentPage = $this->pages[$page]; }
      
      





次に、getPageElementメソッドを記述します。これにより、現在のページから要素、またはそのロケーターを取得できます。



 private function getPageElement($elementName) { //         $curPage = $this->currentPage; return $curPage::getElement($elementName); }
      
      









既に実装されているメソッドの場合、最初に機能テキストから直接受け取った引数をPageObjectの要素で置き換える必要があります。



 $arg
      
      





形になります



 getPageElement($arg))
      
      





次に、メソッドは次の形式を取ります。



 /** * @When     :page */ public function step_beingOnMainPage($page) { //      pageObject $this->currentPage = $this->pages[$page]; $curPage = $this->currentPage; $this->amOnPage($curPage::$URL); } /** * @Then    :element */ public function step_seeElement($element) { $this->waitForElementVisible($this->getPageElement($element)); $this->seeElement($this->getPageElement($element)); } /** * @Then    :button */ public function step_clickOnButton($button) { $this->click($this->getPageElement($button)); } /** * @Then    :field  :text */ public function step_fillField($field, $text) { $this->fillField($this->getPageElement($field), $text); } /** * @Then      :field */ public function step_deleteText($field) { $this->clearField($this->getPageElement($field)); }
      
      





Enterキーを押して検索結果を表示する別の方法を追加しました。



 /** * @Then    ENTER */ public function step_keyboardButton() { $this->pressKey('//input',WebDriverKeys::ENTER); }
      
      





最後のステップは、必要なすべてのメソッドとPageObjectsが記述されたら、テスト自体をリファクタリングする必要があります。 新しいページに移動するときにPageObjectを初期化するステップを追加します。 この「*ユーザーはページにアクセスしました:ページ」があります。



明確にするために、さらにいくつかの手順を追加します。 結果はこのテストです:



 #language: ru :     :   .    .   .      " "     " "     " "     " "      ""     " "  " "     ENTER      " -  "     "   "       " "     " "  ""     ENTER
      
      





このようなテストシナリオは、部外者にとって理解可能で読みやすいものです。



発射!



より詳細な実行結果を表示するには、次のコマンドを使用できます



 cept run acceptance --debug
      
      





結果を見てみましょう:







したがって、ページオブジェクトパターンを使用すると、すべてのページ要素をテストスクリプトから分離し、それらを個別のディレクトリに保存できます。



プロジェクト自体はhttps://github.com/Remneva/ProjectTutorialで見つけることができます



最初の自動化エンジニアとして、アイデアを共有していただければ幸いです。そして、おそらく、プロジェクト構造を可能な限り論理的に変換および簡素化する方法を教えてください。



All Articles