自動化された Web テストをビルド プロセスに統合する
-
11-09-2019 - |
質問
Web サイトの機能テストを自動化するプロセスを改善するための提案を探しています。これが私が過去に試したことです。
以前はテストプロジェクトを使用していました 待っています. 。「単体テスト」のようなものを効果的に作成し、WATIN を使用してブラウザがサイト内をクリックするなどの動作を自動化します。
もちろん、サイトを運営する必要があります。そこで、実際にテストでコードを Web プロジェクトからローカル ディレクトリにコピーし、テストを実行する前にそのディレクトリを指す Web サーバーを起動しました。
そうすれば、新しい人がソース管理から最新のものを取得してビルド スクリプトを実行し、すべてのテストが実行されるのを確認できます。IDE からすべてのテストを単純に実行することもできます。
私が遭遇した問題は、テストよりもテスト環境をセットアップするためのコードのメンテナンスに多くの時間を費やしたことでした。言うまでもなく、コピーのせいで実行に時間がかかりました。また、インストールを含むさまざまなシナリオをテストする必要がありました。つまり、データベースをさまざまな初期状態に設定できる必要がありました。
これらの問題のいくつかを解決し、なおかつシンプルに保つために機能テストを自動化するためにあなたが何を行ったかに興味がありました。
さらに詳しくもっと詳しく知りたいという要望があったので、ここに載せておきます。Visual Studio と Cassini (組み込み Web サーバー) を使用して ASP.NET を実行しています。私の単体テストは MbUnit で実行されます (ただし、それはそれほど重要ではありません。NUnit または XUnit.NET の可能性があります)。通常、私はすべての WATIN テストを別の単体テスト フレームワークで実行します。AssemblyLoad フェーズでは、Web サーバーを起動し、すべての Web アプリケーション コードをローカルにコピーします。
あらゆるプラットフォーム向けのソリューションに興味がありますが、それぞれの意味についてさらに詳しい説明が必要な場合があります。:)
解決
フィル、
自動化は維持するのが難しい場合がありますが、展開に自動化を使用すればするほど、テスト設定に自動化を活用できるようになります (逆も同様です)。
率直に言って、自動化コード以外のビルド ツールを使用すると、自動化コードを進化させ、ファクタリングして特定の小さな機能単位にリファクタリングする方が簡単です。
NAnt や MSBuild の場合と同様、静的にコンパイルされ、事前にファクタリングされた機能単位を駆動するだけです。これが、NAnt のようなツールの比較的初期のユーザーだった多くの人々が Rake に移った理由の 1 つです。Rake では、ビルド コードを他のコードと同じように扱う自由、つまりコンテンツと形状を継続的に進化させる自由がさらに広がります。Rake を使用すると、オートメーション アーティファクトが同じように停滞することがなくなり、NAnt や MSBuild よりも簡単かつ迅速にスクリプトを作成できます。
つまり、苦労の一部は本質的にツールに関係しているのです。自動化を適切に維持するには、NAnt や MSBuild などの静的ビルド ツールが課す障害に注意する必要があります。
アセンブリのロードからテスト環境のブートストラップを結合しないことをお勧めします。それは、一時的な利便性のみを提供する裏返しのカップリングです。IDE またはコマンド ライン、または対話型コンソール (C# REPL など) からテストを実行する前に、コマンド ラインに移動して環境をセットアップするビルド タスクを実行することに何も問題はありません (そして、おそらくすべて正しいです)。 Mono プロジェクト、または IRB から。
テスト データのセットアップは、単に面倒な作業である場合もあります。それはやらなければなりません。
データベースの状態を作成およびクリーンアップするために呼び出すことができるライブラリが必要になります。テスト コードから直接これらの呼び出しを行うこともできますが、テスト データやサンプル データ コントロール コードの有効な使用法が複数あるため、私は個人的にこれを避ける傾向があります。
すべてのサンプル データ制御を HTTP から駆動します。私はサンプル データを制御するためのアクションを備えたコントローラーを作成し、Selenium を介してそれらのアクションに対して GET を発行します。これらをデータの作成とクリーンアップに使用します。これらのアクションへの GET を構成してセットアップ データの一般的なシナリオを作成でき、データの特定の値をリクエスト パラメーター (または必要に応じてフォーム パラメーター) として渡すことができます。
これらのコントローラーは、通常「test_support」と呼ぶ領域に保管します。
Web サイトをデプロイするための自動化では、test_support 領域またはそのルートとマッピングがデプロイされません。デプロイメント検証の自動化の一環として、test_support コードが運用アプリに含まれていないことを確認します。
また、test_support コードを使用して、環境全体の制御を自動化します。サービスを偽のものに置き換えたり、サブシステムをオフにして障害やフェイルオーバーをシミュレートしたり、これらの側面に関係のない機能テストのための認証やアクセス制御をアクティブ化または非アクティブ化したりするなどです。
Web アプリのサンプル データやテスト データを Web から制御することには、次のような大きな副次的な価値があります。アプリをデモするとき、または探索的テストを行うときは、test_support 領域で既知の (または推測可能な) URL に対して get を発行するだけで、必要なデータ シナリオを作成できます。ここでは、休息のとれたルートとリソースの方向性を堅持するという規律ある努力が本当に報われます。
この機能自動化にはさらに多くの作業 (テスト、デプロイメント、デモなど) が含まれるため、これらのリソースが適切に設計されていればいるほど、長いホールでリソースを維持する時間が短縮され、より多くの機会が得られます。予期せぬ、しかし有益な方法でそれらを活用します。
たとえば、Web ページのセマンティック モデル上にドメイン モデル コードを記述すると、より理解しやすいテスト コードを作成し、脆弱性を軽減できます。これをうまく行うと、同じモデルをさまざまな異なるドライバーで使用できるため、ストレス テストや負荷テスト、機能テストで活用できるだけでなく、コマンド ラインから探索ツールとして使用することもできます。ちなみに、この種のことは、静的言語を使用する場合のようにドライバーの種類に束縛されない場合に行うのが簡単です。多くの主要なテスト思想家や実行者が Ruby で働いていること、そして Watir が Ruby で書かれているのには理由があります。Ruby では、C# テスト コードよりも再利用、合成、表現力を実現するのがはるかに簡単です。しかし、それはまた別の話です。
いつか追いついて、この内容の残りの 90% についてもっと話しましょう:)
他のヒント
私たちが使用した プラズマ あるプロジェクトで。これは、プロセス中の Web サーバーをエミュレートします。Web アプリケーション プロジェクトのルートにポイントするだけです。
驚くほど安定していて、ファイルをコピーしたり、プロセス外のサーバーを起動したりすることはありませんでした。
Plasma を使用したテストは次のようになります...
[Test]
public void Can_log_in() {
AspNetResponse response = WebApp.ProcessRequest("/Login.aspx");
AspNetForm form = response.GetForm();
form["UserName"] = User.UserName;
form["Password"] = User.Password;
AspNetResponse loggedIn = WebApp.ProcessRequest(Button.Click(form, "LoginUser"));
Assert.IsTrue(loggedIn.IsRedirect());
AspNetResponse homePage = WebApp.ProcessRequest(loggedIn.GetRedirectUrl());
Assert.AreEqual(homePage.Status, 200);
}
すべての「AspNetResponse」クラスと「AspNetForm」クラスは Plasma に含まれています。
現在、asp.net mvc アプリケーションに自動ビルド プロセスを使用しています。
以下のツールを使用します。
- チームシティ
- SVN
- nUnit
- セレン
任意の数のマシンを使用できるビルド エージェント上で実行される msbuild スクリプトを使用します。msbuild スクリプトは、svn から最新バージョンのコードを取得してビルドします。
成功すると、アーティファクトが特定のマシン/フォルダーにデプロイされ、IIS に仮想サイトが作成されます。
次に、MSBuild contrib タスクを使用して SQL スクリプトを実行し、データベースをインストールし、データをロードします。復元も実行できます。
成功すると、nUnit テストが開始されます。テスト セットアップでは、Selenium が稼働していることを確認し、Watin とほぼ同じ方法で Selenium テストを実行します。Selenium には、C# にエクスポートできるテスト用の優れたレコーダーがあります。
Selenium の良い点は、前回見たときの Watin の場合のように IE に制限されるのではなく、FF、Chorme、IE を駆動できることです。Selenium を使用して Selenium Grid で負荷テストを行うこともできるため、同じテストを再利用できます。
成功すると、msbuild は svn でビルドにタグを付けます。TeamCity には、ビジネス ユーザーが翌朝プロジェクトのステータスを確認できるように、最新のタグをステージング環境にデプロイする夜間に実行されるジョブがあります。
以前は、環境を完全に管理する (Java、Selenium などのインストール) ために nant および msbuild スクリプトがありましたが、これには時間がかかるため、前提条件として、各ビルド エージェントにこれらがインストールされていることを前提としています。いずれこれらのタスクも含める予定です。
なぜコードをコピーする必要があるのでしょうか?Cassini を無視して、Visual Studio に仮想ディレクトリを作成させます。確かに、Web アプリが変更された場合、開発者は Web テストを実行する前に忘れずにビルドする必要があります。特に CI で Web テストを実行する場合、これは大した問題ではないことがわかりました。
データは大きな課題です。私の見る限り、不完全な選択肢の中から選択する必要があります。対処方法は次のとおりです。まず、大規模で複雑な従来の WebForms アプリを扱っていることを説明する必要があります。また、ドメイン コードはテスト プロジェクト内からテスト データを作成するのには適していないことにも言及しておく必要があります。
これにより、いくつかの選択肢が残されました。我々は出来た:(a) ビルドでデータ セットアップ スクリプトを実行するか、(b) 実際の Web サイトを使用して Web テスト経由ですべてのデータを作成します。オプション (a) の問題は、テストが分レベルでスクリプトと結合されることです。Web テスト コードを T-SQL と同期することを考えると、頭がドキドキします。そこで (b) を採用しました。
(b) の利点の 1 つは、セットアップでアプリケーションの動作も検証できることです。問題は...時間.
理想的には、テストは独立しており、時間的な結合がなく (任意の順序で実行可能)、コンテキスト (共通のテスト データなど) を共有していない必要があります。これに対処する一般的な方法は、テストのたびにデータをセットアップして破棄することです。慎重に考えた結果、私たちはこのルールを破ることにしました。
私たちは、戦略をサポートする優れた機能を提供する Gallio (MbUnit 3) を使用しています。まず、フィクスチャ レベルとテスト レベルで実行順序を指定できます。-4、-3、-2、-1 の順に注文された 4 つの「セットアップ」フィクスチャがあります。これらは、指定された順序で、すべての「非セットアップ」フィクスチャの前に実行されます。デフォルトの順序は 0 です。
私たちの Web テスト プロジェクトは、次の 1 つのことのみでビルド スクリプトに依存します。単一の既知のユーザー名/パスワード。これは私が耐えられるカップリングです。セットアップ テストが実行されると、データ (会社、ユーザー、ベンダー、クライアントなど) の識別子を保持する「データ コンテキスト」オブジェクトが構築されます。このオブジェクトは、後で他のすべてのフィクスチャ全体で使用されます (ただし変更されることはありません)。(識別子とは必ずしもキーを意味するわけではありません。ほとんどの場合、Web UI は一意のキーを公開しません。真の識別子の名前または他のプロキシを使用してアプリを操作する必要があります。これについては以下で詳しく説明します。)
Gallio では、テストまたはフィクスチャが別のテストまたはフィクスチャに依存することを指定することもできます。前例が失敗すると、依存関係はスキップされます。これにより、多くの混乱を招く可能性のある「カスケード障害」が防止され、一時的な結合の悪影響が軽減されます。
各テストの前ではなく、ベースライン テスト データを 1 回作成すると、作業が大幅に高速化されます。ただし、セットアップ テストの実行には 10 分かかる場合があります。新しいテストに取り組んでいるときは、テストを頻繁に実行および再実行したいと考えています。もう 1 つの優れた Gallio 機能を入力してください。雰囲気。Ambience は、オブジェクトを永続化する非常に簡単な方法を提供する DB4 のラッパーです。データ コンテキストを自動的に永続化するためにこれを使用します。したがって、セットアップ テストは、データベースの再構築の間に 1 回だけ実行する必要があります。その後、他のフィクスチャのいずれかまたはすべてを繰り返し実行できます。
では、テストデータをクリーンアップするにはどうすればよいでしょうか?既知の状態から始める必要はないでしょうか?これは破るのが得策であると私たちが判断したルールです。私たちにとって有効な戦略は、会社名、ユーザー名などに長いランダム値を使用することです。他のデータと衝突しないように、論理「データ空間」内でテストの実行を維持することは、それほど難しくないことがわかりました。確かに、何時間も費やして幻の失敗テストを追跡した結果、それがデータの衝突であることが判明する日が来るのではないかと心配しています。現在のところ、それがうまく機能しているトレードオフです。
ワチンを使用しています。めっちゃ好きだよ。成功のもう 1 つの鍵は、スコット ベルウェア氏がほのめかしたものです。テストを作成するとき、UI の抽象モデルを構築します。したがって、これの代わりに:
browser.TextField("ctl0_tab2_newNote").TypeText("foo");
これはテストで確認できます。
User.NotesTab.NewNote.TypeText("foo");
このアプローチには 3 つの利点があります。まず、マジックストリングを繰り返すことはありません。これにより脆性が大幅に軽減されます。次に、テストは非常に読みやすく、理解しやすくなります。最後に、Watin フレームワークの大部分を独自の抽象化の背後に隠します。2 番目の例では、TypeText のみが Watin メソッドです。これにより、フレームワークの変更に応じて変更が容易になります。
お役に立てれば。
Maven を使用してビルド プロセスに統合テスト フェーズを組み込むのは困難でしたが、不可能ではありませんでした。何が起こったのかというと、本質的には次のようなことです。
- 統合テストフェーズが開始されない限り、特定のディレクトリ内のすべての JUnit テストを無視します。
- 統合テストを実行するための Maven プロファイルを追加します。
統合前テスト段階の場合 -
Jetty を開始して、テスト データベースにアクセスするアプリケーションを実行します。
- Seleniumサーバーを起動します
- 統合テストフェーズで Selenium 統合テストを実行する
- Seleniumサーバーを停止します
- セレンをやめる
このステップの実際の難しさは、jetty をセットアップすることでした。戦争から起動するだけでは済まなかったので、実際には、jetty に戦争を展開させてからサーバーを実行する必要がありました。しかし、それはうまく機能し、自動化されています。 mvn -PintegrationTest (これが統合テストのプロファイル名です) と入力するだけで完了します。
ビルド完了後に自動的にテストを開始するということでしょうか?自動スクリプトを作成して、ビルドが正常にコンパイルされている間にビルド ファイルを動作中の IIS にコピーすることができます。次に、mstest.exe またはその他のメソッドを呼び出して、自動化された BVT を開始します。
autoitx や Python、Ruby などの関数言語を試してみるのもいいでしょう。