加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala:如何在specs2中实现这个匹配器

发布时间:2020-12-16 18:03:43 所属栏目:安全 来源:网络整理
导读:我有以下方法: def save(entity: A): Either[List[Error],A] + {.... 我想用specs2测试 我想在未指定必填字段时测试是否存在特定错误,如下所示: val noNickname = User( nickname = "",name = "new name",)noNickname.save must beLeft.like { case errors
我有以下方法:

def save(entity: A): Either[List[Error],A] + {....

我想用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")
      }
    }
  }
}

它工作正常,但我想定义自己的匹配器,使其更简洁,像这样:

noNickname.save must haveError.like {
    case error => {
      error.errorCode must equalTo(Error.REQUIRED)
      error.field must equalTo("nickname")
    }
  }
}

我查看了文档(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)
    }
  }
}

请注意,匹配器在[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)
}

[更新]

第一个解决方案(使用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)
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读