概要
Selenium WebdriverでWebの自動テストを行う構成の1例
準備
Selenium Webdriverによるテスト作成の設定について。
Gradleの場合、build.gradleのdependenciesに以下を追加
compile 'org.seleniumhq.selenium:selenium-java:2.32.0'
手動の場合は下記よりjarを取得してクラスパスに追加します。
http://selenium.googlecode.com/files/selenium-java-2.33.0.zip
http://selenium.googlecode.com/files/selenium-server-2.33.0.zip
selenium-java-2.33.0.jar
selenium-server-standalone-2.33.0.jar
ブラウザのDriver
各ブラウザのDriverには以下のようなものがあります。
Driver | Comment |
---|---|
HtmlUnitDriver | GUIでブラウザを動かさないため早い。開発用に。画面が表示されないのでキャプチャ不可 |
FirefoxDriver | FireFox用のドライバ ※今動かない |
InternetExplorerDriver | InternetExplorer用のドライバ |
ChromeDriver | GoogleChrome用のドライバ |
構成
クラス | 内容 |
---|---|
IntegratedTest.java | テストの実行用。複数のシナリオを実行可能 |
/scenario/ |
シナリオ。複数のオペレーションをまとめるもの。 |
/operation/ |
シナリオに含まれる1つのオペレーション。ページの呼び出しとアサーションが主 |
/pages/ |
1つの画面に対応したクラス。画面に対する操作を共通化することが目的。Seleniumラッパーを利用した画面操作の実装が主 |
/util/Selenium.java | SeleniumDriverをラップして利用 |
ソースコード
IntegratedTest
IntegratedTest.java
package gr.java_conf.tb.devhelper.integrated; import gr.java_conf.tb.devhelper.integrated.operation.Operator; import gr.java_conf.tb.devhelper.integrated.scenario.Scenario; import gr.java_conf.tb.devhelper.integrated.scenario.SearchTbpgScenarioFactory; import gr.java_conf.tb.devhelper.integrated.util.Selenium; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.experimental.theories.DataPoints; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; import org.junit.runner.RunWith; import org.openqa.selenium.htmlunit.HtmlUnitDriver; /** * 結合テストシナリオ実行クラス. * * @author tbpgr * */ @RunWith(Theories.class) public class IntegratedTest { private static Selenium DRIVER = null; @BeforeClass public static void classSetup() { DRIVER = new Selenium(new HtmlUnitDriver()); } @Before public void setUp() { } @AfterClass public static void classTearDown() { } @After public void tearDown() { DRIVER.quit(); } @DataPoints public static Scenario[] getScenario() { Scenario[] scenarios = {new SearchTbpgScenarioFactory().getScenario(DRIVER, 1, "シナリオタイトル"),}; return scenarios; }; @Theory public void testIntegrated(Scenario scenario) { try { for (Operator operator : scenario.getOperators()) { System.out.println(operator.getOperation()); operator.operate(); } } catch (Exception e) { e.printStackTrace(); } } }
scenario
Scenario.java
package gr.java_conf.tb.devhelper.integrated.scenario; import gr.java_conf.tb.devhelper.integrated.operation.Operator; import java.util.List; public class Scenario { private int caseNo; private String caseTitle; private List<Operator> operators; public Scenario() { } public int getCaseNo() { return caseNo; } public Scenario caseNo(int caseNo) { this.caseNo = caseNo; return this; } public String getCaseTitle() { return caseTitle; } public Scenario caseTitle(String caseTitle) { this.caseTitle = caseTitle; return this; } public List<Operator> getOperators() { return operators; } public Scenario operators(List<Operator> operators) { this.operators = operators; return this; } @Override public String toString() { return "Scenario [caseNo=" + caseNo + ", caseTitle=" + caseTitle + ", operators=" + operators + "]"; } }
ScenarioFactory.java
package gr.java_conf.tb.devhelper.integrated.scenario; import gr.java_conf.tb.devhelper.integrated.util.Selenium; /** * シナリオ. * * <pre> * テストのシナリオ。 * {@code getScenarioに1つのシナリオを表す{@code Scenario}を実装したクラスを返却する * </pre> * * @author tbpgr * */ public interface ScenarioFactory { Scenario getScenario(Selenium selenium, int caseNo, String caseTitle); }
SearchTbpgScenarioFactory.java
package gr.java_conf.tb.devhelper.integrated.scenario; import gr.java_conf.tb.devhelper.integrated.operation.GoogleTopPageInitialize; import gr.java_conf.tb.devhelper.integrated.operation.MoveToResultSite; import gr.java_conf.tb.devhelper.integrated.operation.SearchGoogle; import gr.java_conf.tb.devhelper.integrated.util.Selenium; import java.util.Arrays; /** * GoogleでTbpgを検索するシナリオ. * * <pre> * ・トップページを開く * ・「tbpg programming memo」で検索を実行する * ・検索結果のリンクから「http://d.hatena.ne.jp/tbpg/」へ遷移する * </pre> * * @author tbpgr * */ public class SearchTbpgScenarioFactory implements ScenarioFactory { public Scenario getScenario(Selenium selenium, int caseNo, String caseTitle) { Scenario scenario = new Scenario() .caseNo(caseNo) .caseTitle(caseTitle) .operators( Arrays.asList(new GoogleTopPageInitialize(selenium), new SearchGoogle(selenium, "tbpg programming memo"), new MoveToResultSite(selenium, "programming memo", "http://d.hatena.ne.jp/tbpg"))); return scenario; } }
Selenium
package gr.java_conf.tb.devhelper.integrated.util; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; /** * Selenium Driverラッパー. * * @author tbpgr * */ public class Selenium { private WebDriver driver; /** * Webdriverを指定して初期化. * * @param driver Webdriver */ public Selenium(WebDriver driver) { this.driver = driver; } /** * 指定{@code url}のページをリクエストする. * * @param url 任意のURL */ public void requestPage(String url) { driver.get(url); } /** * 現在のページのURLを取得する. * */ public String getUrl() { return driver.getCurrentUrl(); } /** * IDでDOM要素を取得する. * * @param id ID * @return DOM要素 */ public WebElement getElementById(String id) { return driver.findElement(By.id(id)); } /** * Class名でDOM要素を取得する. * * @param className Class名 * @return DOM要素 */ public WebElement getElementByClassName(String className) { return driver.findElement(By.className(className)); } /** * nameでDOM要素を取得する. * * @param name name * @return DOM要素 */ public WebElement getElementByName(String name) { return driver.findElement(By.name(name)); } /** * 指定した{@code name}の要素にvalueをテキストする. * * @param name name * @param value 入力文字列 */ public void inputText(String name, String value) { WebElement element = driver.findElement(By.name(name)); element.sendKeys(value); } /** * textの文字列を含むリンクを取得して押下する. * * @param text リンクに含まれる文字列 */ public void link(String text) { WebElement link = driver.findElement(By.partialLinkText(text)); link.click(); } /** * Webdriverを停止する. */ public void quit() { driver.quit(); } /** * 指定したURLと現在のURLが同一か検証する. * * @param expectedUrl 期待値となるURL */ public void assertSameUrl(String expectedUrl) { assertThat(getUrl(), is(expectedUrl)); } /** * 指定したURLが現在のURLに含まれるなら真を返す * * @param expectedUrl 期待値となるURL * @return 指定したURLが現在のURLに含まれるなら真,そうでないなら偽 */ private boolean isContainUrl(String expectedUrl) { return getUrl().contains(expectedUrl); } /** * 指定したURLが現在のURLに含まれるか検証する. * * @param expectedUrl 期待値となるURL */ public void assertContainUrl(String expectedUrl) { assertThat(isContainUrl(expectedUrl), is(true)); } }
operation
Operator.java
package gr.java_conf.tb.devhelper.integrated.operation; /** * テストシナリオに含めるオペレーション. * * @author tbpgr * */ public interface Operator { public String getOperation(); public void operate(); }
GoogleTopPageInitialize.java
package gr.java_conf.tb.devhelper.integrated.operation; import gr.java_conf.tb.devhelper.integrated.page.GoogleTopPage; import gr.java_conf.tb.devhelper.integrated.util.Selenium; /** * Googleトップページ初期化のオペレーション. * * @author tbpgr * */ public class GoogleTopPageInitialize implements Operator { private static final String OPERATION_NAME = "Googleトップページの表示"; String URL = "http://www.google.co.jp/webhp?hl=ja"; private Selenium selenium; public GoogleTopPageInitialize(Selenium selenium) { this.selenium = selenium; } @Override public void operate() { GoogleTopPage top = new GoogleTopPage(selenium); top.openTop(); selenium.assertSameUrl(URL); } @Override public String getOperation() { return OPERATION_NAME; } }
SearchGoogle.java
package gr.java_conf.tb.devhelper.integrated.operation; import gr.java_conf.tb.devhelper.integrated.page.GoogleTopPage; import gr.java_conf.tb.devhelper.integrated.util.Selenium; /** * Googleトップページから検索オペレーション. * * @author tbpgr * */ public class SearchGoogle implements Operator { private static final String OPERATION_NAME = "任意のワードで検索の実行"; private Selenium selenium; private String word; public SearchGoogle(Selenium selenium, String word) { this.selenium = selenium; this.word = word; } /** * Googleトップページで検索を行う. */ @Override public void operate() { GoogleTopPage top = new GoogleTopPage(selenium); top.search(word); } @Override public String getOperation() { return OPERATION_NAME; } }
MoveToResultSite.java
package gr.java_conf.tb.devhelper.integrated.operation; import gr.java_conf.tb.devhelper.integrated.page.SearchPage; import gr.java_conf.tb.devhelper.integrated.util.Selenium; /** * 指定リンク押下オペレーション. * * @author tbpgr * */ public class MoveToResultSite implements Operator { private static final String OPERATION_NAME = "検索結果の指定ページヘ遷移する"; private Selenium selenium; private String linkText; private String expectedUrl; public MoveToResultSite(Selenium selenium, String linkText, String expectedUrl) { this.selenium = selenium; this.linkText = linkText; this.expectedUrl = expectedUrl; } /** * {@code linkText}を含むリンクを押下し、移動先が{@code expectedUrl}であることを検証する. */ @Override public void operate() { SearchPage search = new SearchPage(selenium, linkText); search.moveToSite(); selenium.assertContainUrl(expectedUrl); } @Override public String getOperation() { return OPERATION_NAME; } }
page
GoogleTopPage.java
package gr.java_conf.tb.devhelper.integrated.page; import gr.java_conf.tb.devhelper.integrated.util.Selenium; /** * Googleトップページ. * * <pre> * Googleトップページに関わるWeb操作をまとめるクラス。 * </pre> * * @author tbpgr * */ public class GoogleTopPage { private static final String GOOGLE_JA_TOP = "http://www.google.co.jp/webhp?hl=ja"; private static final String GOOGLE_SEARCH_BUTTION_NAME = "btnG"; private static final String GOOGLE_SEARCH_INPUT_ID = "q"; private Selenium DRIVER = null; public GoogleTopPage(Selenium driver) { super(); DRIVER = driver; } /** * トップページを開く. */ public void openTop() { DRIVER.requestPage(GOOGLE_JA_TOP); } /** * {@code word}で検索を行う. * * @param word 検索ワード */ public void search(final String word) { DRIVER.inputText(GOOGLE_SEARCH_INPUT_ID, word); DRIVER.getElementByName(GOOGLE_SEARCH_BUTTION_NAME).click(); } }
SearchPage.java
package gr.java_conf.tb.devhelper.integrated.page; import gr.java_conf.tb.devhelper.integrated.util.Selenium; /** * Google検索ページ. * * <pre> * Google検索ページに関わるWeb操作をまとめるクラス。 * </pre> * * @author tbpgr * */ public class SearchPage { private Selenium driver = null; private String linkText = null; public SearchPage(Selenium driver, String linkText) { this.driver = driver; this.linkText = linkText; } /** * 検索結果の中にあるリンクを押下する. */ public void moveToSite() { driver.link(linkText); } }