ScalaTestを使っていて便利な機能があったので小ネタとして紹介してみます。
OptionValues
Option
型の値を検証したいときに、 OptionValues
を使うとOption値が定義されているかとその値についての検証を同時に行うことができます。
http://www.scalatest.org/user_guide/using_OptionValues
opt.get should be > 9
opt should be ('defined)
opt.get should be > 9
import org.scalatest.OptionValues._
opt.value should be > 9
class ExampleSpec extends WordSpec with Matchers with OptionValues {
}
実際やってみるとこんな感じです。
import org.scalatest.{Matchers, OptionValues, WordSpec}
class ExampleSpec extends WordSpec with Matchers with OptionValues {
"Option value is defined" in {
val opt: Option[Int] = Some(10)
opt.value should be > 9
}
"Option value is defined but is not match condition" in {
val opt: Option[Int] = Some(1)
opt.value should be > 9
}
"Option value is not defined" in {
val opt: Option[Int] = None
opt.value should be > 9
}
"Option value is not defined and access with get" in {
val opt: Option[Int] = None
opt.get should be > 9
}
}
以下はテスト実行時の出力。注目してほしい点は3番目と4番目のテストの違いで、 value
を使った場合はテストの失敗内容が簡潔にまとめられて出力されていますが、 get
を使った場合は通常の例外における出力(Exceptionのメッセージ + スタックトレース)となっています。
[info] ExampleSpec:
[info] - Option value is defined
[info] - Option value is defined but is not match condition *** FAILED ***
[info] 1 was not greater than 9 (ExampleSpec.scala:12)
[info] - Option value is not defined *** FAILED ***
[info] The Option on which value was invoked was not defined. (ExampleSpec.scala:17)
[info] - Option value is not defined and access with get *** FAILED ***
[info] java.util.NoSuchElementException: None.get
[info] at scala.None$.get(Option.scala:349)
[info] at scala.None$.get(Option.scala:347)
[info] at ExampleSpec.$anonfun$new$4(ExampleSpec.scala:22)
[info] at ExampleSpec$$Lambda$5658/224979600.apply(Unknown Source)
[info] at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
[info] at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
[info] at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
[info] at org.scalatest.Transformer.apply(Transformer.scala:22)
[info] at org.scalatest.Transformer.apply(Transformer.scala:20)
[info] at org.scalatest.WordSpecLike$$anon$1.apply(WordSpecLike.scala:1078)
[info] ...
[info] ScalaTest
[info] Run completed in 436 milliseconds.
[info] Total number of tests run: 4
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 3, canceled 0, ignored 0, pending 0
[info] *** 3 TESTS FAILED ***
[error] Failed: Total 4, Failed 3, Errors 0, Passed 1
[error] Failed tests:
[error] ExampleSpec
[error] (Test / testOnly) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 2 s, completed 2018/08/26 11:35:09
EitherValues, TryValues, PartialFunctionValues
OptionValues
と同じような働きをするtraitは他にもあって EitherValues
TryValues
PartialFunctionValues
というものがあります。これも中の値の定義と検証を同時に行い、失敗した場合は TestFailedException
を起こしてくれます。
http://www.scalatest.org/user_guide/using_EitherValues
http://www.scalatest.org/user_guide/using_PartialFunctionValues
(なぜかTryValuesについてのページは存在しない😅)
import org.scalatest.TryValues._
val try1: Try[Int] = Try { 100 / 10 }
val try2: Try[Int] = Try { 1 / 0 }
try1.success.value should be > 9
try2.failure.exception should have message "/ by zero"
import org.scalatest.EitherValues._
val either1: Either[String, Int] = Right(10)
val either2: Either[String, Int] = Left("Muchas problems")
either1.right.value should be > 9
either2.left.value should be ("Muchas problemas")
import org.scalatest.PartialFunctionValues._
val pf: PartialFunction[String, Int] = Map("I" -> 1, "II" -> 2, "III" -> 3, "IV" -> 4)
pf.valueAt("IV") should equal (4)