复杂的自定义匹配器

Complex custom Matcher

我正在为 API 中某些 API 调用的 Json 输出编写测试,使用 Scala 上的 Play 编写。在我的测试中,这种模式不断出现,我想对其进行去重。

val response = sut.index()(FakeRequest())
val expected = Json.parse("""{ "channels":[] }""")

status(response) must equalTo(OK)
contentType(response) must beSome.which(_ == "application/json")
contentAsJson(response) mustEqual expected

我的第一个方法是这样的:

def assertSameJson(response: Future[Result], expected: JsValue): Unit = {
  status(response) must equalTo(OK)
  contentType(response) must beSome.which(_ == "application/json")
  contentAsJson(response) mustEqual expected
}

但这一点都不符合习惯。好像我在我的规范中添加了 xUnit 断言

我想要一些导致

的东西
response must beSameJson(expected)

我做到的最接近的事情是

def beSameJson(other:Any) = 
  be_==(other) ^^ ((t: Future[Result]) => contentAsJson(t)) and
  be_==(OK) ^^ ((t: Future[Result]) => status(t))

但这并没有检查内容类型,我觉得它很难阅读。 这个Matcher有没有更好的写法?

我认为没有更好的方法来做到这一点。 ^^ 运算符就是为了这个目的而存在的,以便在应用其他匹配器之前转换信息。 and 可用于组合两个以上的匹配器。

所以你唯一能做的就是试着把它写得更干净一点:

def beSameJson(data: String) = 
  equalTo(OK) ^^ {status(_: Future[Result])}
  and beSome.which(_ == "application/json")  ^^ {contentType(_: Future[Result])}
  and be_==(other) ^^ {contentAsJson(_: Future[Result])}

如果您需要更频繁地分解响应,您可以尝试更通用地执行此操作

object Dummy extends Matcher[Any] {
  def apply[S <: Any](s: Expectable[S]) = {
    result(true,
      s.description + " is ignored",
      s.description + " is ignored",
      s)
  }
}

def beResponseWhere(json: Matcher[JsValue] = Dummy, stat: Matcher[Int] = Dummy, tpe: Matcher[Option[String]] = Dummy) =
  stat ^^ {status(_: Future[Result])}
  and tpe ^^ {contentType(_: Future[Result])}
  and json ^^ {contentAsJson(_: Future[Result])}
}

您可能应该使用更好的参数名称(对于此示例,我试图避免与上下文中的方法发生冲突)并且在可用属性上更加完整。

现在你应该可以这样写了:

response must beResponseWhere(
  json = equalTo(expected),
  tpe = beSome.which(_ == "application/json"),
  stat = equalTo(OK)
)

DummyMatcher 允许您省略一些部分。 我显然没有尝试此代码,因为我没有您的完整设置。我还不得不猜测一些从您的代码片段中不清楚的类型。