せっかくSelenium WebDriverを使ったのなら、Mavenの組み込みJettyを使って受け入れテストを自動化したいところ…。
って、この本の受け売りですけどね。
Apache Maven 3クックブック Javaソフトウェア開発のための特選レシピ集
- 作者: Srirangan,長尾高弘
- 出版社/メーカー: アスキー・メディアワークス
- 発売日: 2012/03/02
- メディア: 大型本
- 購入: 7人 クリック: 89回
- この商品を含むブログ (12件) を見る
ただ、この本に載っているのは、SeleniumでもWebDriverではないので、ちょっと古い?あと、Jettyに関する設定もJetty 6で止まっている様なので、いくつか読み替えてみました。
作ったサンプルの構成は、こんな感じです。
webdriver-webapp-example/src/test/java/webdriver/webapp/example/WebDriverIntegration.java webdriver-webapp-example/src/test/java/webdriver/webapp/example/SimpleLogicTest.java webdriver-webapp-example/src/main/webapp/WEB-INF/web.xml webdriver-webapp-example/src/main/webapp/WEB-INF/view/index.jsp webdriver-webapp-example/src/main/webapp/WEB-INF/view/next.jsp webdriver-webapp-example/src/main/java/webdriver/webapp/example/SimpleLogic.java webdriver-webapp-example/src/main/java/webdriver/webapp/example/SimpleServlet.java webdriver-webapp-example/pom.xml
*「webdriver-webapp-example」はプロジェクト名です
まずは、pom。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>webdriver.webapp.example</groupId> <artifactId>webdriver-webapp-example</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>webdriver-webapp-example Maven Webapp</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <build> <finalName>webdriver-webapp-example</finalName> <plugins> <!-- コンパイル設定 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.0</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> <!-- Jetty Pluginの設定(integration-testフェーズ前後で起動/停止) --> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>8.1.8.v20121106</version> <executions> <execution> <id>start-jetty</id> <goals> <goal>run</goal> </goals> <phase>pre-integration-test</phase> <configuration> <scanIntervalSeconds>0</scanIntervalSeconds> <daemon>true</daemon> </configuration> </execution> <execution> <id>stop-jetty</id> <goals> <goal>stop</goal> </goals> <phase>post-integration-test</phase> <configuration> <stopKey>stop</stopKey> <stopPort>9999</stopPort> </configuration> </execution> </executions> </plugin> <!-- integration-testフェーズでの実行設定 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>2.13</version> <executions> <execution> <id>integration-test</id> <goals> <goal>integration-test</goal> </goals> <configuration> <includes> <include>**/*Integration.java</include> </includes> </configuration> </execution> <execution> <id>verify</id> <goals> <goal>verify</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>2.28.0</version> <scope>test</scope> </dependency> </dependencies> </project>
超長い(笑)。この時点で、ちょっと嫌に…。
まあ、依存関係にサーブレットAPIとJUnit、Seleniumを足しているのはいいとして…Jettyプラグインを使って結合テストの前にJettyを起動させ、終わったらシャットダウンするように設定しています。
<plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>8.1.8.v20121106</version> <executions> <execution> <id>start-jetty</id> <goals> <goal>run</goal> </goals> <phase>pre-integration-test</phase> <configuration> <scanIntervalSeconds>0</scanIntervalSeconds> <daemon>true</daemon> </configuration> </execution> <execution> <id>stop-jetty</id> <goals> <goal>stop</goal> </goals> <phase>post-integration-test</phase> <configuration> <stopKey>stop</stopKey> <stopPort>9999</stopPort> </configuration> </execution> </executions> </plugin>
しかしまあ、「jetty-maven-plugin」って…。
続いて、falesafeプラグインを使って結合テスト時に実行するテストの設定。
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>2.13</version> <executions> <execution> <id>integration-test</id> <goals> <goal>integration-test</goal> </goals> <configuration> <includes> <include>**/*Integration.java</include> </includes> </configuration> </execution> <execution> <id>verify</id> <goals> <goal>verify</goal> </goals> </execution> </executions> </plugin>
今回は、ファイル名が「Integration.java」で終わるものを結合テスト対象としています。
つまり、以下の動作を想定しています。
フェーズ | 動作させるテストコード |
単体テスト(test) | ファイル名が「Test.java」で終わるもの |
結合テスト(integration-test) | ファイル名が「Integration.java」で終わるもの |
作ったアプリの動作は、1度サーブレットが受けてフォワードする簡単なものです。
SimpleServlet -> FORWARD -> index.jsp (サブミット後) SimpleServlet -> FORWARD -> next.jsp
まあ、遷移先はパラメータ指定してますが…。
サーブレットは、中で簡単なJavaクラスを呼び出しているのでこちらを単体テストの対象にします。WebDriverは、ブラウザ越しにサーブレットをテストします。
用意したソースは、それぞれこちら。
src/main/java/webdriver/webapp/example/SimpleServlet.java
package webdriver.webapp.example; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/simple") public class SimpleServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String next = request.getParameter("next"); if (next == null) { next = "index.jsp"; } String value = request.getParameter("value"); if (value != null) { request.setAttribute("decoratedValue", new SimpleLogic().decorate(value)); } request.getRequestDispatcher("/WEB-INF/view/" + next).forward(request, response); } }
src/main/javawebdriver/webapp/example/SimpleLogic.java
package webdriver.webapp.example; public class SimpleLogic { public String decorate(String value) { return "***" + value + "***"; } }
src/main/webap/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> </web-app>
src/main/webapp/WEB-INF/view/index.jsp
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <html> <head> <title>index.jsp</title> </head> <body> <p>入力フォーム</p> <form action="/simple" method="get"> <label>入力値:</label><input type="text" name="value" /> <input type="hidden" name="next" value="next.jsp" /> <br /> <input type="submit" value="送信" /> </form> </body> </html>
src/main/webapp/WEB-INF/view/next.jsp
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <html> <head> <title>next.jsp</title> </head> <body> <span id="result">${decoratedValue}</span> </body> </html>
単体テストコードはこちら。
src/test/java/webdriver/webapp/example/SimpleLogicTest.java
package webdriver.webapp.example; import static org.junit.Assert.*; import static org.hamcrest.CoreMatchers.*; import org.junit.Test; public class SimpleLogicTest { @Test public void Helloを渡した場合() { SimpleLogic sut = new SimpleLogic(); String expected = "***Hello***"; assertThat(sut.decorate("Hello"), is(expected)); } }
結合テストコードはこちら。
src/test/java/webdriver/webapp/example/WebDriverIntegration.java
package webdriver.webapp.example; import static org.junit.Assert.*; import static org.hamcrest.CoreMatchers.*; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.firefox.FirefoxDriver; public class WebDriverIntegration { @Test public void WebDriverを使ったテスト() { WebDriver driver = new FirefoxDriver(); try { driver.get("http://localhost:8080/simple"); assertThat(driver.getTitle(), is("index.jsp")); assertThat(driver.findElement(By.name("next")).getAttribute("value"), is("next.jsp")); driver.findElement(By.name("value")).sendKeys("Hello"); driver.findElement(By.tagName("form")).submit(); assertThat(driver.findElement(By.id("result")).getText(), is("***Hello***")); } finally { driver.quit(); } } }
テストの内容は、超適当…。
とまあ、この設定で
$ mvn test
で単体テストまでが実行され、
$ mvn integration-test
で単体テストとSelenium WebDriverを使った結合テストが実行されます。
*単体テスト1ケース、結合テスト1ケースが実行されます
今回は単体テスト側の設定は特にしていませんが、こちらも名前とかで絞るのであればmaven-surefire-pluginで設定するんでしょうね。
http://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html
あとは、src/test/javaに一緒にするんじゃなくて、src/it/javaにしてしまうとか…。
結合テスト用の「maven-failsafe-plugin」は、情報が少なーい。
面倒だろうなぁと思ってやってみましたが、実際に面倒でした。特にJettyと結合テストを組み合わせるところが、もう…。