PHP + BDD = Behat、または奇跡の図書館の物語

Ruby開発に真剣に取り組んでいる人なら誰でも、すばらしいCucumber gemを知っています。 要するに、BDDで強化された自動テスト用のライブラリです。 詳細については、 dapi habrayuzerの トピックをご覧ください 。または、Rain Batesのポッドキャストをご覧ください。 「キュウリ」の主な魅力は、人が理解できる言語でテストを書くことができ、必ずしも英語である必要がないことです。 次のようになります。

機能:追加 
  愚かな間違いを避けるために 
  数学バカとして 
   2つの数字の合計を教えてもらいたい 

  シナリオ:2つの数字を追加する 
    電卓に50を入力したとします
      そして、私は電卓に70を入力しました
     追加を押すと
     その後、結果はスクリーで120になるはずです

Cucumberのおかげで、レール上のBDDに夢中になりました。 しかし、ほとんどの時間で作業しなければならないPHPでは、BDDとの関係はどういうわけかうまくいきませんでした。 そしてまず第一に、きちんとしたツールがないためです。 しかし、ある日、運命は私をBehatライブラリページ (ちなみに、everzet habrayuzerが書いた )に連れて行ってくれました。 そして、私に幸せが降りかかった...

インストールとプリセット


実際、Behatは「PHPの世界からきゅうり」です。 同じ構文( ガーキン言語を使用)、同じファイル構造、ステップを決定するためのほぼ同一の方法。 著者は、彼が隠していない図書館の「兄」に触発されたことがわかります。 すべてが美しく見えますが、私たちはそれを見ませんでした。 動作中の製品を試す時間です。

すぐに予約します-Behatの作業にはPHP 5.3.1が必要です。 したがって、まだ入手していない場合は、それを行う時間です。

サイトの作成者は、Behatをインストールするいくつかの方法を提供しています。 一番最初で最も簡単なものを選択します-Pearを通じて:
$ pear channel-discover pear.everzet.com
$ pear install everzet/behat-beta

タダム! 私たちはBehatの幸運な所有者です:)原則として、テスト済みプロジェクトのあるフォルダーに移動してスクリプトの作成を開始することもできますが、ライブラリを少し「調整」することを好みます。 それでは、まず、プロジェクトフォルダーにBehatのネイティブハビタットを作成しましょう。 既に述べたように、Cucumberから借用されており、次の形式を持っています。

 |-機能
    `-ステップ
    |  `-* _steps.php
    `-サポート
        `-env.php


私たちが持っているものの詳細:

env.phpファイルは最初は空です。 私たちにとっての主な重要性は、次のスクリプトの実行前に毎回実行されることです。 そして、ここに必要なすべてのライブラリとプロジェクトファイルを接続すると便利です。 また、テストに必要な変数と関数を定義することも便利です。 ちなみに、それらのストレージには、$ world変数を使用するのが非常に便利です。これは、入力するたびに、新しいたびに提供されます。 概して、基本的な機能を使用するために、何も設定する必要はありません。BehatとPHP自体が提供してくれれば十分です。 しかし、私はまだPHPUnitの検証関数を使用したいので、許可を得てそれらを接続します。

PHPUnitがインストールされていない場合、同じPearを介して非常に簡単にインストールされます。
$ pear channel-discover pear.phpunit.de
$ pear channel-discover components.ez.no
$ pear channel-discover pear.symfony-project.com
$ pear install phpunit/PHPUnit

完了、env.phpに登録するだけです:
 <?php
 require_once 'PHPUnit / Autoload.php';
 require_once 'PHPUnit / Framework / Assert / Functions.php';
 ?>

また、プロジェクトのクラスと関数を使用できるようにするには、適切なファイルを環境に接続する必要があります。 環境の初期化に余分なインクルードを散らかしたくないので、それらを1つのファイル-includes.phpに結合し、すでに環境に接続します。 その結果、env.phpファイルの形式は次のとおりです。

 <?php
 require_once 'PHPUnit / Autoload.php';
 require_once 'PHPUnit / Framework / Assert / Functions.php';
 include 'includes.php';
 ?>

機能について説明し、最初のリリースを行います


さて、これでテストの準備ができました。機能の説明を始めることができます。 例として、2つの数字を追加するなど、実装とテストが難しいものを採用することにしました。 したがって、 機能フォルダーにcalc.featureファイルを作成し、 次のように記述します。

機能:追加
    愚かな間違いを避けるために 
    数学バカとして 
     2つの数字の合計を教えてもらいたい

    シナリオ:
       電卓があると
        最初の番号として30を入力したとき
         そして、2番目の番号として20を入力しました
         そして、「追加」を押します
        その後、結果は50になります


コマンドを保存してコンソールに入力します
$ behat features

出力は次のとおりです。
 1つのシナリオ(1つの未定義)
 5ステップ(5未定義)
 0.091秒

次のスニペットを使用して、未定義のステップのステップ定義を実装できます。

 $ steps->与えられた( '/ ^私は電卓を持っています$ /'、function($ world){
     new \ Everzet \ Behat \ Exception \ Pending();
 });

 $ steps-> When( '/ ^ I are(\ d +)as first number $ /'、function($ world、$ arg1){
     new \ Everzet \ Behat \ Exception \ Pending();
 });

 $ steps-> And( '/ ^ I are(\ d +)as second number $ /'、function($ world、$ arg1){
     new \ Everzet \ Behat \ Exception \ Pending();
 });

 $ steps-> And( '/ ^ I press \'([^ \ '] *)\' $ / '、function($ world、$ arg1){
     new \ Everzet \ Behat \ Exception \ Pending();
 });

 $ steps-> Then( '/ ^結果は(\ d +)$ /'、function($ world、$ arg1){
     new \ Everzet \ Behat \ Exception \ Pending();
 });

これは、シナリオの「ステップ」を定義していないことを示しています。 しかし、私たちはさらに多くを知っています-計算機クラスはありません。 問題ではなく、書いてください。

クラスCalc {
    保護された$ first = 0;
    保護された$秒= 0;
    保護された$ result = 0;

    パブリック関数setFirst($ num){$ this-> first = $ num;  }
    パブリック関数setSecond($ num){$ this-> second = $ num;  }
     public function add(){$ this-> result = $ this-> first + $ this-> second;  }
     public function getResult(){return $ this-> result;  }
 }

手順を説明し、テストを成功させます。


それでは、ステップの説明に移ります。 はい、ちなみに、ファイル機能/サポート/includes.phpの計算機のクラスにファイルを含めることを忘れないでください。 ご覧のとおり、Behatは親切に手順を定義するためのパターンを提供してくれました。 それらをコピーして少し調整し、 features / steps / calc_steps.phpファイルに保存します 。 次のようなものが得られるはずです。
 <?php
 $ steps->与えられた( '/ ^私は電卓を持っています$ /'、function($ world){
     $ world-> calc = new Calc();
 });
 $ steps-> when( '/ ^ Iが最初の数字$ /'として(\ d +)を入力した場合、function($ world、$ num){
     $ world-> calc-> setFirst($ num);
 });
 $ steps-> When( '/ ^ Iが2番目の数値$ /'として(\ d +)を入力した場合、function($ world、$ num){
     $ world-> calc-> setSecond($ num);
 });
 $ steps-> When( '/ ^ I press \' Add \ '$ /'、function($ world){
     $ world-> calc-> add();
 });
 $ steps-> Then( '/ ^結果は(\ d +)$ /'、function($ world、$ res){
     assertEquals($ res、$ world-> calc-> getResult());
 });
 ?>

テストを再開します-出来上がりです! テストに合格しました:)

機能:追加
  愚かな間違いを避けるために
  数学バカとして
   2つの数字の合計を教えてもらいたい

  シナリオ:#features / calc.feature:6
    計算機#features / steps / calc_steps.phpがある場合:5
    最初の番号として30を入力した場合#features / steps / calc_steps.php:9
    そして、2番目の番号として20を入力しました#features / steps / calc_steps.php:13
    そして、「追加」を押します#features / steps / calc_steps.php:17
    その後、結果は50#features / steps / calc_steps.phpになるはずです:21

 1シナリオ(1合格)
 5ステップ(5合格)
 0.114秒

ページをテストしようとしています。


もちろん、クラスの動作をテストすることはプロジェクトの重要な部分です。 しかし、顧客は、いつものように、私たちからの作業クラスではなく、正しく機能する(彼の意見では)アプリケーションを望んでいます。 簡単に言えば-彼はインターフェイスの正しい操作が必要です。 現在の動作の検証。 Ruby on Railsは従来、cucumer + webrat + nokogiriを使用してページをテストします。 PHPの世界では、すべてが少し複雑であることが判明しました...そのページにあるエバーゼット自体は、このためにSymfony 2に基づいたGoutteライブラリを使用することを示唆しています。 、登録解除してください)。 Goutteのインストールは非常に簡単です。pharアーカイブをダウンロードしてenv.phpに接続します。

テストの例として、簡単なページをスケッチしました。
 <!DOCTYPE html>
 <html>
     <head>
     </ head>
     <本体>
         <div> <?
             if($ _GET ["submit"]){
                 echo "Text ="。  $ _GET ['textfield']。  "<br />";
                 echo "Checkbox ="。  $ _GET ['チェックボックス']。  "<br />";
                 echo "Radio ="。  $ _GET ['radio']。  "<br />";
                 echo "Select ="。  $ _GET ['selectbox']。  "<br />";
             }
         ?> </ div>
         <form method = "get" action = "behat.php">
             <div>
                 <input type = "text" name = "textfield" value = "">
             </ div>
             <div>
                 <入力タイプ=「チェックボックス」名前=「チェックボックス」値=「チェックボックス」>
             </ div>
             <div>
                 <入力タイプ= "ラジオ"名前= "ラジオ"値= "ラジオ1"チェック= "チェック">
                 <入力タイプ= "radio" name = "radio" value = "radio2">
                 <入力タイプ= "radio" name = "radio" value = "radio3">
             </ div>
             <div>
                 <select name = "selectbox">
                     <option value = "option1" selected = "selected"> option1 </ option>
                     <option value = "option2"> option2 </ option>
                     <option value = "option3"> option3 </ option>
                 </ select>
             </ div>
             <div>
                 <入力タイプ=「送信」名前=「送信」値=「送信」>
             </ div>
             <div id = "linkdiv">
                 <a href="behat.php?textfield=text&checkbox=checkbox&radio=radio3&selectbox=option2&submit=Submit">クリック</a>
             </ div>
         </ form>
     </ body>
 </ html>

タスク:そのフォームの動作を確認します。 はい、タスクは非常に合成的ですが、これは単なる例です:)それで、テストのリストをカバーします:
機能:テスト
    フォームを送信した後、フィールドのすべての値
    ページの上部に表示する必要があります

    シナリオ:フィールドを埋める
        私がテストページにいると仮定して
          「送信」フォームで「テキストフィールド」に「テキスト」を入力すると
          そして、フォーム 'Submit'を送信します
         次に、「テキスト=テキスト」が表示されます

    シナリオ:チェックボックスをオンにする
        私がテストページにいると仮定して
         フォーム「送信」のチェックボックス「チェックボックス」にチェックマークを付けると
          そして、フォーム 'Submit'を送信します
         次に、「チェックボックス=チェックボックス」が表示されます

    シナリオ:ラジオの選択
        私がテストページにいると仮定して
          「Submit」フォームの「radio」ラジオで「radio2」を選択すると
          そして、フォーム 'Submit'を送信します
         次に、「Radio = radio2」が表示されます
         その後、「Radio = radio1」が表示されないはずです

    シナリオ:選択ボックスでオプションを選択する
        私がテストページにいると仮定して
         フォーム「送信」の選択ボックス「selectbox」で「option3」を選択すると
          そして、フォーム 'Submit'を送信します
         次に、「Select = option3」が表示されます
         その後、「Select = option1」が表示されないはずです

    シナリオ:いくつかのフィールドを埋める
        私がテストページにいると仮定して
         フォーム「Submit」に以下を入力すると:
             | テキストフィールド| テキスト|
             | チェックボックス| 真|
             | ラジオ|  radio3 |
             | セレクトボックス| オプション2 |
          そして、フォーム 'Submit'を送信します
         次に、「テキスト=テキスト」が表示されます
          そして、私は「チェックボックス=チェックボックス」が表示されるはずです
          そして、「Radio = radio3」が表示されるはずです。
          そして、「div」内に「Select = option2」が表示されるはずです。

    シナリオ:リンクをクリックする
        私がテストページにいると仮定して
          「#linkdiv」内の「Click me」リンクをクリックすると
         次に、「テキスト=テキスト」が表示されます
          そして、私は「チェックボックス=チェックボックス」が表示されるはずです
          そして、「Radio = radio3」が表示されるはずです。
          そして、「div」内に「Select = option2」が表示されるはずです。
          そして、「Submit」フォームの「textfield」フィールドは空白にする必要があります


テストのフォームが「送信」と呼ばれる理由の簡単な説明。 Goutteでは、フォームは送信ボタンで選択されます。 ボタン自体はIDまたは値で検索されます。 そして、テストページのボタンは誇らしげにSubmitという名前になっているため、この言葉遣いです。

多くの手順があり、手順は異なり、誰もがGoutteでの作業に関与しています。 幸いなことに、これらのすべての手順はすでに説明されており、ファイルにまとめられています。 gitリポジトリgit://github.com/DarthSim/behat_websteps.gitから目的のものをプルできます。 リポジトリには次のものがあります。

階層を保持したまま、プロジェクトと共にフォルダーにファイルをコピーし、テストを実行します。 そして、エラーが発生します...

Unknown path 'test page'. You can define it in [features_folder]/support/paths.php

エラーはそれ自体を物語っています-テストは、どの種類の「テストページ」をチェックしたいかを知りません。 最も簡単な修正方法は、 features / support / paths.phpファイルで 「テストページ」ページのパスを設定することです 。 テストページがtests.dev/behat.phpにあるとします 。そのため、パスファイルに次のように記述する必要があります。

$world->paths['test page'] = "http://tests.dev/behat.php";

テストを実行します-素晴らしい、テストに合格しました! 残りのステップの分析は、webratの類似物に似ているため、読者に任せます。 もちろん、結果の機能はwebratよりもはるかに劣っていますが、これはほんの始まりに過ぎないと思います。

結論を導き、リンクを提供する


したがって、BehatはPHPの世界でCucumberの後継にふさわしいと言っても過言ではありません。 ライブラリはまだバージョン1.0に成長していませんが、すでに高品質の完成品を表しています。 私たちは、開発者が彼の発案の開発に成功することを望み、彼に良い光線を送ります。 以下は便利なリンクです。

githubのBehatリポジトリ
Behat WIKI
Behat API
Goutteリポジトリ
Symfony 2 API (Goutteに役立ちます)

Source: https://habr.com/ru/post/J110422/


All Articles