Selenium と Cucumber を使用した自動テスト

RIA の自動テストを作成し、バッチ実行する

シンプルなフィーチャー (feature) ファイルにテストを記述し、ブラウザーでスイッチを切り替えてこのテストを実行する方法を習得することにより、Selenium と Cucumber を使用したテストを自動化する作業を楽なものにしてください。この記事は、Selenium と Cucumber を使用したテスト自動化フレームワークのセットアップ、シングル・ページ Web アプリケーション用のテスト・スイートの作成、そして Selenium Grid による複数の Web/モバイル・ブラウザーでのテストを行うための実践的な入門ガイドです。

Alan Bowers, Web and Mobile Consultant, IBM

Alan BowersAlan Bowers は、IBM Software Group の Software Services for Mobile Team に所属する Web 2.0 およびモバイルに関するコンサルタントで、2011年4月から現在の職務に就いています。彼はこの職務に就いてから、完全な開発ライフサイクルおよびアジャイル開発手法や、広範に及ぶ Web 技術 (特に JavaScript、Dojo、jQuery、および Worklight) に携わってきました。現在の職務に就く前は、Java ベースのアプリケーションを対象とした診断ツールを開発している小さなアジャイル・チームで Java 開発者として働いていました。



James Bell, Managing Consultant, IBM

James BellJames Bell は、Global Business Services に所属する、IBM Interactive のコンサルタントで、技術ソリューションに関する指導、管理、開発の経験があります。彼は、国内向けおよび国外向けのデリバリー・チームを率いて、大規模なプロジェクトと小規模なプロジェクトの両方に携わってきました。



2014年 1月 23日

Web アプリケーションの開発ライフサイクルにおいては、サポート対象のブラウザーで Web アプリケーションが確実に動作し続けるようにすることが不可欠です。これまで Web アプリケーションの開発者は、広範囲に及ぶリグレッション・テストを実行することで、さまざまなブラウザーでアプリケーションが確実に動作するようにしてきましたが、この方法では時間とリソースの両面でコストがかかります。これに代わる方法としては、一連のブラウザーで実行可能な、完全に自動化されたテストで構成される複数のテスト・スイートを作成するという方法があります。

スケジューリングされたビルド・プロセスの一環として、またはビルド・パイプラインの一環として、完全に自動化されたテスト・スイートを構築して実行することができます。いずれの場合も、早期に問題を検出して迅速なフィードバックを得ることができるというメリットがあります。ビルドが進められる頃までには、開発者はアプリケーション・コードが正常に動作することを確信しているはずなので、これにより、リグレッション・テストの必要性を大幅に低減したり、完全に排除したりすることさえできます。

この記事では、自動テストに Selenium と Cucumber を使用するメリットを具体的な例を用いて説明します。このフレームワークを使用する場合、ビジネス・マネージャーをはじめとする非技術系の利害関係者にも理解できる形でフィーチャー (feature) ファイルにテストを記述し、そのテストを、複数のスクリプト言語やプログラミング言語をサポートする Cucumber によって Java 言語に変換します。Selenium はブラウザーを駆動するために使用します。

ここでは、Cucumber と Selenium を使用して Java ベースの自動テスト・フレームワークをセットアップするプロセス全体を説明します。まず、Cucumber でフィーチャー・ファイルにテストを記述する方法を紹介してから、変更されたページ・オブジェクト (Page Object) パターンの実装とともに Selenium を使用する方法、さらにはサポート対象の任意のブラウザーでリッチ・インターネット・アプリケーション (RIA) をテストする方法について説明します。また、Chrome やモバイル・ブラウザーなど、サポート対象外のブラウザーでアプリケーション・コードをテストするための設定についても簡単に具体例を示します。最後に、テスト・スイートを自動化するための、Maven ビルドの設定について確認します。この記事では全体で、保守が可能なソリューションをテストするコードを計画し、実装する方法に重点を置きました。

なお、デモに使用した RIA のモック・アプリケーションはいつでもダウンロードすることができます。

Cucumber を使用したテスト

Cucumber は、ソフトウェア開発者とビジネス・マネージャーの間の橋渡しをする上で役立つテスト・フレームワークです。テストは、専門家以外の人でも理解できる、Given、When、Then を使用したビヘイビア駆動開発 (BDD) のスタイルに基づいた平易な言語で記述され、テスト・ケースは、1 つ以上のテスト・シナリオに対応するフィーチャー・ファイルに配置されます。Cucumber は、テストを解釈して指定のプログラミング言語に変換するとともに、Selenium を使用してテスト・ケースをブラウザーで実行します。ここでは、テストを Java コードに変換します。

デモ・アプリの URL

この記事の例は、デモ・アプリをローカルで URL: http://localhost/MockApplication/html/MockApplication.html から提供していることを前提にしています。このアプリケーションの URL を変更する場合は、それに応じてテスト・コードを更新する必要があります。

BDD の Given、When、Then による構文は、直感的に理解できるように作られています。この構文の要素について検討してみましょう。

  • Given では、これから実行しようとしているテスト・シナリオのコンテキストを指定します。例えば、アプリケーション内でテスト対象となるポイントや、前提条件となるデータがこれに当たります。
  • When では、ユーザー・アクションやサブシステムのアクションなど、テストをトリガーする一連のアクションを指定します。
  • Then では、予想されるテスト結果を指定します。

リスト 1 に、簡単な Web サイトのログイン・テストを示します。ユーザーがこの Web サイトにログオンすると、ログイン・ページにリダイレクトされます。

リスト 1. 初期ログイン・テスト
Feature: Test login

Scenario Outline: Login Success and Failure
	Given I navigate to the mock application
	When I try to login with valid credentials
	Then I should see that I logged in successfully

Cucumber ではテーブルから値を代入できるため、このテストを再利用可能にしようと思えばできます。リスト 1 のテストをリスト 2 に示すような成否テストにリファクタリングすることは非常に容易です。

リスト 2. ログインの成否テスト
@run
Feature: Test Login

Scenario Outline: Login Success and Failure
	Given I navigate to the mock application
	When I try to login with '<type>' credentials
	Then I should see that I logged in '<status>'
	
Examples:
	| type		| status		|
	| valid		| successfully		|
	| invalid	| unsuccessfully	|

Cucumber は指定された場所にあるフィーチャー・ファイルを読み取り、指定されたタグのあるテストを実行します。そのため、例えばテスト・リソース・フォルダーの MockApp というディレクトリーにリスト 2 のテストを配置した場合、リスト 3 に示すような Java テスト・クラスによってこのテストが読み取られます。

リスト 3. サンプル Java テスト・クラス
@RunWith(Cucumber.class)
@Cucumber.Options(
        features = "MockApp",//path to the features
        format = {"json:target/integration_cucumber.json"},//what formatters to use
        tags = {"@run"})//what tags to include(@)/exclude(@~)

public class RunTests {
}

Maven を使用している場合は、リスト 4 の依存関係を POM に追加する必要もあります。

リスト 4. Cucumber の依存関係が追加された Maven の POM
<dependency>
	<groupId>info.cukes</groupId>
	<artifactId>cucumber-core</artifactId>
	<version>${cucumber.version}</version>
</dependency>
<dependency>
	<groupId>info.cukes</groupId>
	<artifactId>cucumber-java</artifactId>
	<version>${cucumber.version}</version>
</dependency>
<dependency>
	<groupId>info.cukes</groupId>
	<artifactId>cucumber-junit</artifactId>
	<version>${cucumber.version}</version>
</dependency>

フィーチャー・ファイルの解釈

フィーチャー・ファイルの行が意味する内容を、まだテストに認識させていないことに注意してください。これを認識させるには、リスト 3 で作成したクラスが含まれるパッケージの中に別のクラスを作成する必要があります。例えば、リスト 5 のクラスは、リスト 2 で作成したフィーチャー・ファイルを解釈し、各ステップを完了するたびにステートメントをログに書き出します。

リスト 5. LoginSteps クラス
public class LoginSteps {
	private static final Logger LOGGER = Logger.getLogger(LoginSteps.class.getName());
	
	@Given("^I navigate to the mock application$")
	public void given_I_navigate_to_the_mock_application(){
		LOGGER.info("Entering: I navigate to the mock application");
	}
	
	@When("^I try to login with '(.+)' credentials$")
	public void when_I_try_to_login(String credentialsType){
		LOGGER.info("Entering: I try to login with " + 
			credentialsType + " credentials");
	}
	
	@Then("^I should see that I logged in '(.+)'$")
	public void then_I_login(String outcome){
		LOGGER.info("Entering: I should see that I logged in " + outcome);
	}
}

各メソッドには、GivenWhen、または Then を使用してアノテーションが付けられ、それぞれのアノテーションにはフィーチャー・ファイルの行に対応する正規表現が含まれます。

Cucumber テストの実行を試みた場合、テストは成功します。成功するのは、まだテスト・コードを記述していないからで、次のセクションではこの作業を行います。


Selenium によるブラウザーの駆動

いくつかのテストを記述したので、次のステップでは Web ブラウザーでこれらのテストを実行します。このために、Cucumber とうまく連携する Web ブラウザー自動化フレームワークである Selenium を使用します。Selenium を使用してブラウザーを駆動する方法には、次の 2 つのツールのいずれかを使用する方法があります。

  1. Selenium RC: Web ページの駆動に JavaScript を使用し、JavaScript サンドボックス内で実行されます。
  2. WebDriver: ネイティブの自動化を使用するため、より高速でエラーも少なくなる傾向がありますが、サポートするブラウザーは少なくなります。

ここでは WebDriver を使用してデモ・アプリをテストします。

ブラウザー・インスタンスを開く

Maven を使用してアプリケーションをビルドしている場合は、POM に以下の依存関係を追加することから始めます。

<dependency>
	<groupId>org.seleniumhq.selenium</groupId>
	<artifactId>selenium-java</artifactId>
	<version>${selenium.version}</version>
</dependency>

次に BrowserDriver というクラスと、ブラウザー・ドライバーを取得するメソッドや終了するメソッドを作成します (リスト 6 を参照)。

リスト 6. BrowserDriver クラス
private static WebDriver mDriver;
	
public synchronized static WebDriver getCurrentDriver() {
	if (mDriver==null) {
		try {
                	mDriver = new FirefoxDriver(new FirefoxProfile());
	        } finally{
	        	Runtime.getRuntime().addShutdownHook(
					new Thread(new BrowserCleanup()));
	        }
	}
	return mDriver;
}

private static class BrowserCleanup implements Runnable {
	public void run() {
		LOGGER.info("Closing the browser");
		close();
	}
}

public static void close() {
	try {
		getCurrentDriver().quit();
		mDriver = null;
		LOGGER.info("closing the browser");
	} catch (UnreachableBrowserException e) {
		LOGGER.info("cannot close browser: unreachable browser");
	}
}

この例では、Firefox を対象とした Web ブラウザー用ドライバーを作成しますが、Selenium でサポートされている任意のブラウザー用のドライバーで置き換えることもできます。また、ドライバーにはシャットダウン・フックも追加します。これで、テストの成功/失敗にかかわらず、テストが完了すると自動的にブラウザーが閉じられるようになります。

次に、ブラウザーが何らかの有用な処理を実行するためのメソッドが必要です。リスト 7 は、ページをロードするメソッドです。これをリスト 6BrowserDriver クラスに追加します。

リスト 7. ページのロード
public static void loadPage(String url){;
	LOGGER.info("Directing browser to:" + url);
	getCurrentDriver().get(url);
}

ブラウザーへのテスト・コードの接続

次に、BrowserDriver のメソッドをテストにフックする必要があります。そこで、テストを実行するための新しいクラス、Navigation を作成します。Navigation クラスは処理をページ・コンテナーに委任します。これについては次のセクションで説明します。

テストを実行するには、そのテスト内のメソッドに対応するメソッドが Navigation クラスに存在する必要があります。例えば、リスト 8 では、Web ページのロードに LoginSteps (リスト 5 を参照) の下記メソッドが使用されています。

リスト 8. BrowserDriver における LoginSteps のメソッド
public void given_I_navigate_to_the_mock_application(){
	BrowserDriver.loadPage(
		"http://localhost/MockApplication/html/MockApplication.html");
}

ここでは、リスト 8 のメソッドを使用して Web ページをロードします。次に、LoginSteps クラスを継承してこのメソッドを呼び出す必要があります。(リスト 5 の) 既存のメソッドをリスト 9 のメソッドで置き換えます。

リスト 9. LoginSteps の新しいメソッド
	@Given("^I navigate to the mock application$")
	public void given_I_navigate_to_the_mock_application(){
		LOGGER.info("Entering: I navigate to the mock application");
		navigation.given_I_navigate_to_the_mock_application();
	}

このコードを実行すると、ブラウザーにモック・アプリケーションがロードされます。


RIA でのページ・オブジェクトの使用

このプロセスの次のステップは、Web ページが正常にロードされていることの確認です。そのために、従来のページ・オブジェクト・パターン (「参考文献」を参照) とは少し異なるバリエーションを導入します。ここでは、このバリエーションを使用して、ページに固有の対話を実行します。

ページ・オブジェクトは、ユーザーと Web ページの間の対話を抽象化して 1 つのオブジェクトにまとめるために使用されます。言うなれば、この 1 つにまとめられたオブジェクトは、Web ページが提供するサービスを表しています。ページ・オブジェクトは、その内部でページの DOM 要素を認識している必要があり、さらには DOM 要素と対話する方法も認識していなければなりません。この実装では、ページ・オブジェクトの「表示」クラスをいくつも呼び出しますが、DOM 参照は区別されて「コンテナー」クラスに含められます。

ここでの実装と、ページ・オブジェクトの通常の実行方法との大きな違いは、ページが実際に表す内容にあります。従来の Web アプリケーションでは、サーバーへリクエストが送信される度に、新しいページが返されるため、ページ・オブジェクトは Web ページ全体になります。最近のシングル・ページ Web アプリケーションでは、各セクションが表示されていたり表示されていなかったりする状態で、複数のページが最初に返されます。シングル・ページ・アプリケーションでは、ページ・オブジェクトが Web ページ全体を表すようにしても意味がないので、そうせずに、ページ・オブジェクトがページの中で自己完結したセクションを表すようにします。

サンプル・アプリケーションに含まれるセクションには、ログイン・ビューとホーム・ビューがあります。このアプリケーションでは一度に 1 つのセクションしか表示されませんが、もっと大きなアプリケーションでは同時に複数のセクションが表示される場合があります。さらに、新しいページが毎回返されるということがないため、サーバーへのリクエストに付随する処理がいつ完了したかを認識することが課題となります。例えば、ユーザーが無効な資格情報を使用してログインしようとすると、おそらく画面にエラーを表示することになります。リクエストに付随する処理が完了したことを認識し、それに応じてテストを行うには、エラー表示を受け取るまで、または定義済みの最大時間が経過するまで、ポーリングする必要があります。

ビュー内での DOM の探索

DOM 探索の実装コードを見てみましょう。まず、LoginContainer というコンテナー・クラスを作成する必要があります。このクラスはログイン・ビューの DOM 要素を見つけるために使用されます。ここでは、DOM の探索に @FindBy アノテーションを使用します。このアノテーションは、探索対象を指定するパラメーターを受け取ります。リスト 10 では、探索に How パラメーターを使用し、探索変数として using を使用しています。How のオプションには、CSS、ID、および XPATH があります。

リスト 10. DOM 探索を含む LoginContainer
	@FindBy(how = How.ID, using = "LoginPage")
	public WebElement loginPageDiv;
	
	@FindBy(how = How.CSS, using = "#LoginPage input[name=username]")
	public WebElement usernameInput;
	
	@FindBy(how = How.CSS, using = "#LoginPage input[name=password]")
	public WebElement passwordInput;
	
	@FindBy(how = How.CSS, using = "#LoginPage span[role='button']")
	public WebElement submitButton;

次に、LoginPage クラスを作成します。テスト・アプリケーションのログイン・ページとの対話には、このクラスを使用します。

ブラウザーがこのアプリケーションのサイトにリダイレクトされたときに、ログイン・ページが表示されることを確認する必要があります。そこで、新しい LoginView クラスの isDisplayedCheck() メソッド (リスト 11) を呼び出すように、Navigationgiven_I_navigate_to_the_mock_application() メソッドを編集します。

リスト 11. ログイン・ページが表示されることを確認する
	public static void isDisplayedCheck(){
		LOGGER.info("Checking login page is displayed");
		BrowserDriver.waitForElement(loginContainer.loginPageDiv);
		loginContainer.loginPageDiv.isDisplayed();
	}

これで OK です。私たちは、ブラウザーでこのアプリケーションのサイトにナビゲートしたときにログイン・ページが表示されるかどうかをテストしました。このテストは、私たちのフィーチャー・ファイルの最初のシナリオでした。次に、ユーザーが問題なくログインできるかどうかをテストします。


資格情報を使用したログイン

リスト 2 に戻ってフィーチャー・ファイルを見てみると、テストの次のフェーズは、ユーザーが <type> 資格情報を使用して Web ページへのログインを試みたときに何が起きるかを確認することであることがわかります。この場合のタイプ (type) とは、可能性としてあり得る選択肢の 1 つを意味しますが、ここではその選択肢を「valid (有効)」と「invalid (無効)」に絞りました。

Cucumber では任意の文字列型を列挙型に変換することができますが、この方法には制限があります。例えば、「correct (正しい)」と「valid (有効)」で同じ内容を表したい場合、別個の列挙インスタンスを使用しなければなりません。別の方法としては、列挙型の引数として String の配列を使用して探索を実行する方法です。リスト 12 に示すように、このような探索メソッドを列挙型に配置すると、複数の文字列に対して同じ意味を持たせることができます。

リスト 12. 資格情報タイプの列挙
public enum CredentialsType {

   VALID(new String[]{"valid", "correct"}),
   INVALID(new String[]{"invalid"});
	
   private String[] aliases;
	
   private CredentialsType(String[] aliases){
        this.aliases = aliases;
   }

   public static CredentialsType credentialsTypeForName(String credentialsType) 
		throws IllegalArgumentException{
	for(CredentialsType ct: values()){
		for(String alias: ct.aliases){
			if(alias.equalsIgnoreCase(credentialsType)){
				return ct;
			}
		}
	}
	throw credentialsTypeNotFound(credentialsType);
    }

    private static IllegalArgumentException credentialsTypeNotFound(String ct) {
        return new IllegalArgumentException(("Invalid credentials type [" + ct + "]"));
    }
}

次に、指定されたタイプのユーザーを作成します。このユーザーは、テストのステート・マシン (「参考文献」を参照) として実装します。というのも、ユーザー資格情報を後ほどテストで再利用する可能性があるからです。例えば、ユーザーのログイン後にユーザー名が表示されるかどうかを確認する必要が生じる場合があります。テスト内に個々のユーザー・データをハードコーディングする (これはユーザーの詳細情報を複数の場所に配置することを意味します) よりも、ユーザー・ファクトリーを実装する方が効率的です。テスト・ユーザーとユーザー・ファクトリーをリスト 13 に示します。

リスト 13. テスト・ユーザーとユーザー・ファクトリー
public class User {
	private String username;
	private String password;
	
	public User withUserName(String username){
		this.username = username;
		return this;
	}
	
	public String getUsername(){
		return username;
	}
	
	public User withPassword(String password){
		this.password = password;
		return this;
	}
	
	public String getPassword(){
		return password;
	}
	
}

public class Users {
	public static User createValidUser(){
		User user = new User();
		user.withUserName("username").withPassword("password");
		return user;
	}
	
	public static User createInvalidUser(){
		User user = new User();
		user.withUserName("").withPassword("");
		return user;
	}
}

次に、リスト 14 のメソッドを Navigation クラスに追加し、これを呼び出すように LoginSteps 内の該当するメソッドを変更します。

リスト 14. Navigation クラスのログイン・メソッド
private User user;

public void when_I_try_to_login(String credentialsType) {
	CredentialsType ct = CredentialsType.credentialsTypeForName(credentialsType);
	switch(ct){
		case VALID:
			//create a valid user
			user = Users.createValidUser();
		break;
		case INVALID:
			//create an invalid user
			user = Users.createInvalidUser();
		break;
	}
	//try to login
	LoginView.login(user.getUsername(), user.getPassword());
}

最後のステップは、リスト 15 に示すように、LoginView クラスに login メソッドを作成することです。このメソッドは前に作成した loginContainer クラス (リスト 10) を使用します。このクラスは、関連する DOM 要素を見つける方法を示してくれます。これらの要素を囲む Selenium ラッパーには、これらの要素との対話を可能にする便利なメソッドがいくつかあります。ここで必要になるメソッドは、ユーザー名とパスワードを入力ボックスに入力できるようにする sendKeys と、ログインの詳細情報を送信できるようにする click の 2 つです。

リスト 15. LoginView クラスの login メソッド
public static void login(String username, String password){
	LOGGER.info("Logging in with username:"+username+" password:"+password);
	loginContainer.usernameInput.sendKeys(username);
	loginContainer.passwordInput.sendKeys(password);
	loginContainer.submitButton.click();
	LOGGER.info("Login submitted");
}

この時点でテストを実行すると、ユーザー名とパスワードが適切な入力要素の中に入力され、その後で「Submit (送信)」ボタンがクリックされるのを確認できます。完全な実装コードについては、この記事の「ダウンロード」を参照してください。


各種ブラウザーでのテスト

ここまでは、Opera、Safari、および Internet Explorer と並んで、特別な設定をしなくても Selenium WebDriver でサポートされている Firefox のみをテスト対象の Web ブラウザーとして、テスト・ケースを実行してきました。しかし少し手を加えるだけで、Chrome、iOS、Android、Opera Mobile の各ブラウザーに対してもテスト・ケースを実行できるようになります。

実行時に -Dbrowser=safari などのシステム・プロパティーを渡すことによって、比較的容易にブラウザーを切り替えられることがわかっています。テストでは、リスト 16 のコードを使用して、このシステム・プロパティーを読み取ることができます。

リスト 16. テスト・ブラウザーを指定する
Browsers browser;
WebDriver driver;
		
if(System.getProperty(BROWSER_PROP_KEY)==null){
	browser = Browsers.FIREFOX;
}else{
	browser=Browsers.browserForName(System.getProperty(BROWSER_PROP_KEY));
}
switch(browser){
	case CHROME:
		System.setProperty("webdriver.chrome.driver", 
"src/main/resources/chromedriver");
		driver = new ChromeDriver();
		break;
	case SAFARI:
		driver = new SafariDriver();
		break;
	case FIREFOX:
		default:
		driver = new FirefoxDriver();
		break;
}

動的なテスト・データ

テスト・データの保守は、自動テストで判明した最大の問題の 1 つです。テストを新しい環境に移す際には、すべてのテスト・データを手動でセットアップしなければならないような事態は避けたいものです。また、そのデータが変更された場合に、すべてのテスト・ケースでデータを更新しなければならないという事態も避けたいものです。こうした問題に対処する 1 つの方法としては、テストの開始時に、関連するデータベースや Web サービスとやりとりすることで、動的にテスト・データを作成できるようにする方法があります。

Browsers は、実行対象のブラウザーが列挙された独自の列挙体を表すオブジェクトであることに注意してください。

Chrome に対してテスト・ケースを実行するには、自分で Chrome ドライバーをダウンロードし、リスト 16 に示すようにシステム・プロパティー "webdriver.chrome.driver" に、ダウンロードしたドライバーの場所を設定します。


テストおよびビルド環境

テストをローカルで実行できれば大変結構なのですが、テストをビルドに接続できなければ意味がありません。最後に、Selenium Grid (「参考文献」を参照) を使用して、ビルド・マシンから一度に複数のテストを実行する方法を紹介します。

まず、テスト・マシン上で Selenium Grid をセットアップします。次に、-Dremote=true などのシステム・プロパティーを渡します。これにより、単一のローカル・ブラウザーの実行からグリッドに対する実行へとテストを切り替えられるようになります。

後は、ブラウザーのドライバーを更新するだけです。以前に私たちは、リスト 17 のコードを使用してローカルの Firefox Web ドライバーを作成しました。

リスト 17. テスト・ブラウザーとして Firefox を指定する
case FIREFOX:
	driver = new FirefoxDriver();
	break;

リスト 18 のようにコードを変更すると、ローカル・ドライバーとグリッドとの間で切り替えられるようになります。

リスト 18. リモートのテスト・ブラウザーを指定する
case FIREFOX:
	String isRemote = System.getProperty("remote");
	if("true".equalsIgnoreCase(isRemote);{
		DesiredCapabilities firefox = DesiredCapabilities.firefox();
           firefox.setVersion("17");
           firefox.setPlatform(Platform.ANY);
           driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), firefox);
	else{
		driver = new FirefoxDriver();
	}
	break;

リスト 18 の URL には Selenium Grid ハブのアドレスを指定する必要があります。

テスト・スイートの実行

アプリケーションをビルドしてデプロイしたら、そのアプリケーションに対してテストを実行する必要があります。テストを行う 1 つの方法は、単一の大規模なテスト・スイートの一部としてすべてのテストを実行することです。しかしテストの数が増えてくると、この設定ではあまりにも時間がかかりすぎることに気付くでしょう。これに代わる別の方法として、最初から小さなテスト・スイートでテストをバッチ実行する方法があります。フィーチャー・ファイルの先頭でさまざまなアノテーション・タグを使用することで、テストをグループ化することができます。例えば @login タグを使用すると、すべてのログイン・テストを 1 つのテスト・スイートにグループ化することができます。この場合、リスト 19 に示すように、スイートごとに関連付けられた Java クラスが必要になります。

リスト 19. テスト・バッチの実行
@RunWith(Cucumber.class)
@Cucumber.Options(
        features = "MockApp",//path to the features
        format = {"json:target/integration_cucumber.json"},//what formatters to use
        tags = {"@login"})//what tags to include(@)/exclude(@~)
public class RunTests {
}

まとめ

Web アプリケーションのテスト用に自動化されたフレームワークをセットアップすることは難しい作業ではありますが、長期的には取り組む価値があるのは明らかです。Selenium と Cucumber を使用すると、この作業が大幅に簡単になり、保守が可能なテスト・スイートが実現することがわかりました。この記事では、Selenium と Cucumber を使用してリッチ・インターネット・アプリケーションを対象とした自動テスト・スイートをセットアップすることに重点を置きましたが、フィーチャー・ファイルの記述方法と使用方法についても簡単に紹介し、各種ブラウザーでアプリケーション・コードを容易にテストする方法のヒントも示しました。以下に挙げる領域で綿密な計画を立てると、時間が経過するにつれて、その作業の見返りを得られるようになります。

  • テスト・データの保守を複数の環境に対して行うことは、テスト自動化における難題となることが予測できます。テスト自動化フレームワークをデータベースまたは Web サービス・インフラストラクチャーに接続することにより、実行前にテスト・ケースで必要なデータを動的にセットアップできるようになります。
  • フィーチャー・ファイルのインタープリター (リスト 5 を参照) は、短期間でサイズが非常に大きく、取り散らかったファイルになる可能性があります。何かがうまくいかないときに何千行ものテスト・コードの中を探し回らなくても済むように、新しいテストを作成する際には各ステップを適切にドキュメントにしてください。
  • テストの実行に非常に長い時間がかかる場合があります。これは多数の異なるブラウザーに対してテストを実行する必要がある場合は、なおのことです。妥当な時間でテストを完了するには、Selenium グリッドに接続する必要があるブラウザーの数を (そして可能であれば、マシンの数も) 綿密に計画してください (ただし、複数のブラウザーを 1 つのマシン上で実行することもできます)。

ダウンロード

内容ファイル名サイズ
Sample codea-automating-ria-src.zip10MB

参考文献

学ぶために

  • 万人のためのオートメーション」(Paul Duvall 著): この developerWorks の連載で、テスト自動化と継続的インテグレーションについてさらに詳しく学んでください。
  • アジャイル DevOps: テスト駆動型インフラストラクチャー」(Paul Duvall 著、developerWorks、2012年11月): Cucumber で Gherkin を使用してフィーチャー・ファイルを作成する方法についてのより詳しい説明を読んでください。
  • Selenium 2 を導入する」(Sebastiano Armeli-Battana 著、developerWorks、2012年4月): Selenium WebDriver と Selenium Grid を使用して機能テストについての理解を深めてください。
  • Manage time and resources better by scheduling automated tests」(Vaibhav Rangare 著、developerWorks、2011年6月): 効率的で保守が可能なテスト・スイートを計画する方法について紹介した記事で、自動テストの概要を理解してください。
  • Selenium: Page Objects (Selenium Wiki): テストの自動化にページ・オブジェクト・パターンを使用する方法について詳しく学んでください。
  • Why developers should be force-fed state machines」(Willem van Bergen 著、Shopify、2011年6月): Web 開発およびテストの両方でステート・マシンを使用する方法 (そして、ステート・マシンを使用する理由) を理解してください。

製品や技術を入手するために

  • Cucumber: プレーン・テキストでテストを作成し、Java コードで実行してください。
  • Selenium: モバイル・ブラウザーを含む、ほとんどの Web ブラウザーに対応したテスト自動化スイートです。
  • Selenium Grid: 複数のブラウザーに自動テストを分散することができます。

議論するために

  • developerWorks コミュニティーに参加してください。ここでは他の developerWorks ユーザーとのつながりを持てる他、開発者によるブログ、フォーラム、グループ、Wiki を調べることができます。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source
ArticleID=960542
ArticleTitle=Selenium と Cucumber を使用した自動テスト
publish-date=01232014