2011年06月11日

JettyをScalaから起動してHTTP関連のテストで使ってみる

・前書き

HTTP通信関連のテストをする時に、あまり他所様に連続リクエストをするのは好ましくない。なのでlocalhostにテストファイルを置いてテストケースを実行することがある。

これまではApacheのhtdocsに放り込んでやってたのだけど、環境が変わるたびにlocalhostにファイルを用意する作業が必要になってしまうのがイマイチ。

こんな時、他のプロジェクトではどうしてるのかなぁと思ってHTTPClientのテストコードを見てみると、LocalTestServerという自前のテスト用ローカルサーバ機能を用意しているようだった。

LocalTestServerをパクっても良いかとも思ったのだけど、Scalaでlocalhostで静的コンテンツを返すだけなら、彼に任せればいいじゃないかということで、Jettyさんに登場して頂いてみた。



とりあえずJettyを入れる。

Mavenから入れる場合は、レポジトリはここ。
http://repo1.maven.org/maven2/org/eclipse/jetty/

今回はテスト目的なので、scopeをtestにしておく。
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>7.4.2.v20110526</version>
<scope>test</scope>
</dependency>

手動でいれる場合は以下の5つがたぶん必要。
・jetty-server
・jetty-http
・jetty-io
・jetty-util
・jetty-continuation

Jettyで静的コンテンツを利用する場合は、ResourceHandlerを使えばいいらしい。

サーバ起動のためのコードはこんな風になる。
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.server.handler.ResourceHandler

val handler = new ResourceHandler
handler.setResourceBase("htdocs")
val server = new Server(8083)
server.setHandler(handler)
server.start
server.join

プロジェクト直下にhtdocsというフォルダを掘って、上記コードを実行して、http://localhost:8083/foo.htmlを開くと、htdocs配下のfoo.htmlの内容が見れる。

実質的なコードはわずか6行。静的ファイルを開くだけなら、こんなに簡単。

実際にテストする場合は、setUpでサーバを起動して別スレッドでjoinして、tearDownでserverに対してstopを発行すれば良いような気がする。

Specsで適当に書いたらこんな感じになった。なんかServerあたりはもっとマシな書き方があるような気がする。Specs2もまだ触れてないし、この辺はそのうち勉強し直そう。
import scala.concurrent.ops.spawn
import org.junit.runner.RunWith
import org.specs.runner.JUnitSuiteRunner
import org.specs._
import org.specs.matcher._
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.server.handler.ResourceHandler

object HttpClientTest {
val server = new Server(8083)
}

@RunWith(classOf[JUnitSuiteRunner])
class HttpClientTest extends SpecificationWithJUnit {

doBeforeSpec {
val handler = new ResourceHandler
val resourceUrl = getClass.getClassLoader.getResource("test-htdocs")
handler.setResourceBase(resourceUrl.getPath)
HttpClientTest.server.setHandler(handler)
HttpClientTest.server.start
spawn { HttpClientTest.server.join }
}

"てすと1" should {
"てすと2" in { true must_== true }
"てすと3" in { true must_== true }
}
"てすと4" in { true must_== true }

doAfterSpec {
HttpClientTest.server.stop
}
}

上記の例では、resourceフォルダの下にtest-htdocsというフォルダを掘って、そこにテスト用ファイルを入れてる。これでコミットしたプロジェクトをpullした後に速攻でテストが実行できてめでたし。
|-- pom.xml
|-- src
|-- main
| |-- resources
| `-- scala
`-- test
|-- resources
| `-- test-htdocs
| `-- foo.html
`-- scala