web-dev-qa-db-ja.com

GUIの機能受け入れテストにより、脆弱性が少なくなり、さらなる開発の障害になります

(背景-要点の太字のステートメントにスキップ)

Freeman&Pryceの「GrowingObject-Oriented Software、Guided by Tests」という本を、自分が始めているプロジェクトに適用しながら作業しています。私のアプリはPHPのWebアプリで、ユーザーのeBayインタラクションを管理します。

Behat/Minkを使用してエンドツーエンドのテストを作成しています。私は最初のテストで立ち往生しています。

この本の中で、彼らは最初にテストを書くことの重要性を強調しています。また、要件の変更やリファクタリングなど、テストが開発の邪魔にならないようにする必要があります。

彼らは、最初のテストでシステムをエンドツーエンドで実行する必要があることを強調しています。例えばデータベースを使用して、eBayなどの外部システムと対話するようにユーザーインターフェイスに命令する。そして、この機能は最小限でなければなりません。

ただし、これは、最初のテストのGUIが将来のテストのためにそのまま残る可能性が低いことを意味します。したがって、GUIへの不可避の変更によってテストが中断されないように、最初の(および後続の)テストは可能な限り柔軟にする必要があります(これには、少なくとも2つの大きな副作用があります。テストを書き直す時間と、書き直されたテストが元のテストで検出されたバグを検出できないリスクです)。後者は私が本当に心配していることです-本「ThePragmaticProgrammer」では、彼らは「バグを見つけるonce "」を強調しています。

それが抽象的な問題です。それを自分のプロジェクトに適用して、最初にユーザーからの購入の記録を蓄積するシステムのスライスを書くことを考えていました。これには、顧客がユーザーから何かを購入することをコミットするたびにアプリケーションを呼び出す通知をeBayに設定することが含まれます。機能テストはそれをシミュレートし、GUIを介して、ユーザーに表示されるリスト(最初は単純な単一のHTMLテーブルとして実装します)に順序が表示されることを確認します。

しかし、顧客が購入を確約すると、Paypal経由で支払う必要があります。アプリが処理するレコードは複雑になります。一部のユーザーはまったく支払わない、一部のユーザーは支払う、一部のユーザーは全額払い戻し、一部払い戻し、複数の払い戻し、メッセージはユーザーと顧客の間で交換される可能性があるため、ユーザーはインターフェイスなどから郵便料金ラベルを印刷します。

したがって、ほとんどの場合、GUIは、最初のテスト機能を満たすために作成されたものから認識できなくなります。

これらの2つの問題にどのように対処するのが最善でしょうか。

  1. GUIテストコードの適応にかかる時間
  2. 以前のテストで検出されたはずの古い機能のバグを検出できない、書き直された古いテストのリスク

私はいくつかのアイデアを思いついたが、それは私を圧倒したパンドラの箱のように感じます、そしておそらく他の本などを参照して、誰かが私を正しい方向に向けることができるかどうか疑問に思います:

  1. 最初のアイデア:変更されないままのBehatテスト(Gherkin)を記述しますが、GUIが変更されるたびにそれらのステートメントを解釈するMinkコードを変更します。これはほとんど問題を解決しませんが、少なくともガーキンステートメントはおそらく修正を必要としないでしょう。
  2. (非常にあいまいなアイデア)GUIレイヤーをできるだけ薄くし、場合によってはGUI専用の複数のウェーハ薄の抽象化レイヤーを作成し、テストで抽象化を一致させます。これにより、GUIの変更が大きな影響を与えるのを防ぐことができます。テストの。 (正直なところ、これがどのように機能するかはわかりません)。
  3. Freeman/Pryceは、「可能な限り最小のステップで変更を加える」というヒントを提供します。これにより、要件/ GUI設計の変更とテストの変更を簡単に関連付けることができます。しかし、最終的にGUIの変更が蓄積されるにつれて、効果のないテストのリスクも蓄積されないかどうかはわかりません。

長い質問をお詫びします。

3
CL22

GUIに一致するGUIテストを作成しないでください。要件に一致する受け入れテストを作成します

次のようにテストを作成できます。

  • ユーザー名フィールドに「user」と入力し、パスワードフィールドに「pass」と入力すると、
  • そして、「ログイン」ボタンをクリックします
  • [ユーザーの検索]ボタンをクリックすると
  • そして、ユーザー名フィールドに「foo」と入力します
  • そして「検索」をクリックします
  • 次に、行「1」にユーザー「JohnnyFoo」が含まれるテーブルが表示されます。
  • そして、行「2」にユーザー「MannyFoo」が含まれるテーブルが表示されます。

または、次のように書くこともできます。

  • パスワード「pass」で「user」としてログインしている場合
  • そして私は「foo」と呼ばれるユーザーを探します
  • 次に、検索結果の行「1」に「JohnnyFoo」が表示されます。
  • また、検索結果の「2」行に「MannyFoo」と表示されます。

最初のものは完全にGUIにあなたを結びつけます。 2つ目は、機能、ストーリー、要件の観点から必要なものにのみ結合します。

このようにして、再利用可能になるコードを記述します。テストの行は機能式であり、これらを具体的なGUI実装に一致させるコードがありますが、GUIで何かが変更された場合は、「」のようなものをマップする場所である1つの場所で変更を加えるだけで済みます。具体的なGUIコードに「foo」というユーザーを探しています。

事例:昨日、作業中のアプリケーションのページを、送信のロードから、JSONとノックアウトを使用したデータのフェッチと表示に切り替えました。つまり、ボタンをクリックして送信を待つ代わりに、データが読み込まれると消える読み込みアニメーションを表示していました。上記の例でこれを試してください。最初の例では、その待機をステップとして追加する必要があります。2番目の例では、「 'foo'というユーザーを探します」という実装とともにタグを付けます。さて、私の最初の例のように見える3つのテストがある場合、汗はありません。しかし、10個ある場合はどうなりますか?または百?

ちなみに、 Behat/Minkとそれが使用するGherkinDSLの例 を見ると、これらは非常に一般的で人間が読める形式の例であることがわかります。これは偶然ではなく、このレベルでテストを作成するときにどのように考えるべきかを示す非常に良い例です。

3
JDT