ope*_*sas 4 testing scala specs2
我有以下方法:
def save(entity: A): Either[List[Error],A] + {....
Run Code Online (Sandbox Code Playgroud)
我想用specs2测试
我想在未指定必填字段时测试是否存在特定错误,如下所示:
val noNickname = User(
nickname = "",
name = "new name",
)
noNickname.save must beLeft.like {
case errors => {
atLeastOnceWhen(errors) {
case error => {
error.errorCode must equalTo(Error.REQUIRED)
error.field must equalTo("nickname")
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
它工作正常,但我想定义自己的匹配器,使其更简洁,像这样:
noNickname.save must haveError.like {
case error => {
error.errorCode must equalTo(Error.REQUIRED)
error.field must equalTo("nickname")
}
}
}
Run Code Online (Sandbox Code Playgroud)
我查看了文档(http://etorreborre.github.com/specs2/guide/org.specs2.guide.Matchers.html#Matchers),但我无法弄清楚如何定义像hasError这样的自定义匹配器.喜欢
这里你的代码有一些改动,使它编译:
case class Error(errorCode: String, field: String)
def save[A](entity: A): Either[List[Error],A] = Left(List(Error("REQUIRED", "nickname")))
case class User(nickname: String, name: String)
val noNickname = User(nickname = "", name = "new name")
"save noNickName" >> {
save(noNickname) must haveError.like {
case error => {
error.errorCode must equalTo("REQUIRED")
error.field must equalTo("nickname")
}
}
}
def haveError[T] = new ErrorMatcher[T]
class ErrorMatcher[T] extends Matcher[Either[List[T], _]] {
def apply[S <: Either[List[T], _]](value: Expectable[S]) =
result(value.value.left.toOption.isDefined,
value.description + " is Left",
value.description + " is not Left",
value)
def like[U](f: PartialFunction[T, MatchResult[U]]) =
this and partialMatcher(f)
private def partialMatcher[U](f: PartialFunction[T, MatchResult[U]]) =
new Matcher[Either[List[T], _]] {
def apply[S <: Either[List[T], _]](value: Expectable[S]) = {
// get should always work here because it comes after the "and"
val errors = value.value.left.toOption.get
val res = atLeastOnceWhen[T, U](errors)(f)
result(res.isSuccess,
value.description+" is Left[T] and "+res.message,
value.description+" is Left[T] but "+res.message,
value)
}
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,匹配器在Either[List[T], _]任何地方都是定义的.
我也想知道在没有找到预期的错误消息的情况下返回的失败消息,当部分函数失败时它们可能不是非常明确.
所以你可能想要使用包含匹配器.像这样:
"save noNickName" >> {
save(noNickname) must haveError.containing(Error("REQUIRED", "nickname"))
}
// I'm reusing the beLeft matcher here
def haveError[T]: Matcher[Either[List[T], _]] = beLeft
// and using an implicit conversion to extend it
implicit def toErrorListMatcher[T](m: Matcher[Either[List[T], _]]): ErrorListMatcher[T] =
new ErrorListMatcher[T](m)
class ErrorListMatcher[T](m: Matcher[Either[List[T], _]]) {
def containing(t: T) =
// the 'contain' matcher is adapted to take in an
// Either[List[T], _] and work on its left part
m and contain(t) ^^ ((e: Either[List[T], _]) => e.left.toOption.get)
}
Run Code Online (Sandbox Code Playgroud)
[更新]
第一个解决方案(使用atLeastOnceWhen和部分函数)可以与第二个解决方案(使用隐式)和beLike匹配器组合,以获得现有规范2代码的最大可重用性:
def haveError[T]: Matcher[Either[List[T], _] = beLeft
implicit def toErrorListMatcher[T](m: Matcher[Either[List[T], _]]): ErrorListMatcher[T] =
new ErrorListMatcher[T](m)
class ErrorListMatcher[T](m: Matcher[Either[List[T], _]]) {
// beLike checks one element
// beLike.atLeastOnce transforms that matcher on a
// matcher on a sequence of elements
def like[S](f: PartialFunction[T, MatchResult[S]]) = {
m and beLike(f).atLeastOnce ^^ ((e: Either[List[T], _]) => e.left.toOption.get)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2496 次 |
| 最近记录: |