テストについて話しましょう。プラグインを作成すると、それは長期的なものになります。新しい機能を追加したり(またはバグを修正したり)し続けるために、テストを書くことは理にかなっています。
sbtにはscriptedテストフレームワークが付属しており、ビルドシナリオをスクリプト化できます。これは、変更検出や部分コンパイルなど、複雑なシナリオでsbt自体をテストするために書かれました。
さて、B.scalaを削除したが、A.scalaを更新しないとどうなるかを考えてみましょう。再コンパイルすると、Aが参照するBが存在しなくなったため、エラーが発生するはずです。[… (本当に複雑なもの)]
scriptedテストフレームワークは、上記のケースのようにsbtがケースを処理することを検証するために使用されます。
このフレームワークは、scripted-pluginを介して利用可能になります。このページの残りの部分では、scripted-pluginをプラグインに含める方法について説明します。
開始する前に、バージョンを**-SNAPSHOT**のものに設定してください。scripted-pluginはプラグインをローカルに公開するためです。SNAPSHOTを使用しないと、あなたと世界中の他の人が異なるアーティファクトを見るという、ひどい一貫性のない状態に陥る可能性があります。
build.sbt
でSbtPlugin
を有効にする
lazy val root = (project in file("."))
.enablePlugins(SbtPlugin)
.settings(
name := "sbt-something"
)
次に、次の設定をbuild.sbt
に追加します。
lazy val root = (project in file("."))
.enablePlugins(SbtPlugin)
.settings(
name := "sbt-something",
scriptedLaunchOpts := { scriptedLaunchOpts.value ++
Seq("-Xmx1024M", "-Dplugin.version=" + version.value)
},
scriptedBufferLog := false
)
**注**:SbtPlugin
を使用するには、sbt 1.2.1以降を使用する必要があります。
ディレクトリ構造src/sbt-test/<テストグループ>/<テスト名>
を作成します。まず、src/sbt-test/<あなたのプラグイン名>/simple
のようなものを試してください。
準備はいいですか?simple
に初期ビルドを作成します。プラグインを使用する実際のビルドのように。手動でテストするために、すでにいくつか持っていると確信しています。これはbuild.sbt
の例です
lazy val root = (project in file("."))
.settings(
version := "0.1",
scalaVersion := "2.10.6",
assembly / assemblyJarName := "foo.jar"
)
project/plugins.sbt
で
sys.props.get("plugin.version") match {
case Some(x) => addSbtPlugin("com.eed3si9n" % "sbt-assembly" % x)
case _ => sys.error("""|The system property 'plugin.version' is not defined.
|Specify this property using the scriptedLaunchOpts -D.""".stripMargin)
}
これは、earldouglas/xsbt-web-plugin@feabb2から得たトリックで、テストにバージョン番号を渡すことができます。
src/main/scala/hello.scala
もあります
object Main {
def main(args: Array[String]): Unit = {
println("hello")
}
}
次に、テストプロジェクトのルートディレクトリにあるtest
というファイルに、シナリオを記述するスクリプトを記述します。
# check if the file gets created
> assembly
$ exists target/scala-2.10/foo.jar
スクリプトの構文は次のとおりです。
#
は1行のコメントを開始します>
name
はタスクをsbtに送信します(そして、それが成功するかどうかをテストします)$
name arg*
はファイルコマンドを実行します(そして、それが成功するかどうかをテストします)->
name
はタスクをsbtに送信しますが、失敗することを期待します-$
name arg*
はファイルコマンドを実行しますが、失敗することを期待しますファイルコマンドは次のとおりです
touch
path+
ファイルを作成またはタイムスタンプを更新しますdelete
path+
ファイルを削除しますexists
path+
ファイルが存在するかどうかを確認しますmkdir
path+
ディレクトリを作成しますabsent
path+
ファイルが存在しないかどうかを確認しますnewer
source target
source
が新しいかどうかを確認しますmust-mirror
source target
source
が同一かどうかを確認しますpause
Enterキーが押されるまで一時停止しますsleep
time
スリープします(ミリ秒単位)exec
command args*
別のプロセスでコマンドを実行しますcopy-file
fromPath toPath
ファイルをコピーしますcopy
fromPath+ toDir
相対構造を維持しながら、パスをtoDir
にコピーしますcopy-flat
fromPath+ toDir
パスをフラットにtoDir
にコピーしますしたがって、スクリプトはassembly
タスクを実行し、foo.jar
が作成されるかどうかを確認します。後でより複雑なテストを取り上げます。
スクリプトを実行するには、プラグインプロジェクトに戻り、次を実行します。
> scripted
これにより、テストビルドが一時ディレクトリにコピーされ、test
スクリプトが実行されます。すべてがうまくいけば、publishLocal
が実行されているのが確認できます。
Running sbt-assembly / simple
[success] Total time: 18 s, completed Sep 17, 2011 3:00:58 AM
ファイルコマンドは素晴らしいですが、どれも実際のコンテンツをテストしていないため、ほとんど十分ではありません。コンテンツをテストする簡単な方法は、テストビルドにカスタムタスクを実装することです。
私のhelloプロジェクトでは、結果のjarが「hello」を出力するかどうかを確認したいと考えています。scala.sys.process.Process
を利用してjarを実行できます。失敗を表現するには、エラーをスローするだけです。これはbuild.sbt
です
import scala.sys.process.Process
lazy val root = (project in file("."))
.settings(
version := "0.1",
scalaVersion := "2.10.6",
assembly / assemblyJarName := "foo.jar",
TaskKey[Unit]("check") := {
val process = Process("java", Seq("-jar", (crossTarget.value / "foo.jar").toString))
val out = (process!!)
if (out.trim != "bye") sys.error("unexpected output: " + out)
()
}
)
テストが失敗する様子を確認するために、意図的に「bye」と一致するかどうかをテストしています。
これがtest
です
# check if the file gets created
> assembly
$ exists target/foo.jar
# check if it says hello
> check
scripted
を実行すると、予想どおりテストが失敗します
[info] [error] {file:/private/var/folders/Ab/AbC1EFghIj4LMNOPqrStUV+++XX/-Tmp-/sbt_cdd1b3c4/simple/}default-0314bd/*:check: unexpected output: hello
[info] [error] Total time: 0 s, completed Sep 21, 2011 8:43:03 PM
[error] x sbt-assembly / simple
[error] {line 6} Command failed: check failed
[error] {file:/Users/foo/work/sbt-assembly/}default-373f46/*:scripted: sbt-assembly / simple failed
[error] Total time: 14 s, completed Sep 21, 2011 8:00:00 PM
コツをつかむまでは、テスト自体が正しく動作するまでに時間がかかる場合があります。役立つ可能性のあるいくつかの手法があります。
最初に始めるのは、ログバッファリングをオフにすることです。
> set scriptedBufferLog := false
たとえば、これは一時ディレクトリの場所を出力するはずです
[info] [info] Set current project to default-c6500b (in build file:/private/var/folders/Ab/AbC1EFghIj4LMNOPqrStUV+++XX/-Tmp-/sbt_8d950687/simple/project/plugins/)
...
Enterキーを押すまでテストを中断するには、次の行をtest
スクリプトに追加します。
$ pause
sbt/sbt-test/sbt-foo/simple
に移動してsbt
を実行しようとしている場合は、実行しないでください。正しい方法は、ディレクトリを別の場所にコピーして実行することです。
sbtプロジェクト自体には、文字通り100以上のスクリプトテストがあります。インスピレーションを得るために閲覧してみてください。
たとえば、これはby-nameと呼ばれるものです。
> compile
# change => Int to Function0
$ copy-file changes/A.scala A.scala
# Both A.scala and B.scala need to be recompiled because the type has changed
-> compile
xsbt-web-pluginおよびsbt-assemblyにも、いくつかのスクリプトテストがあります。
以上です!プラグインのテストに関する経験を教えてください!