Specs2 JSONMatchers:映射数组元素?

时间:2013-11-20 12:06:10

标签: scala specs2

我正在使用Specs2 JSONMatcher来验证GET请求是否正在从其内部表示中正确转换(在生成JSON之前我们做了一些操作)。我需要做的是,确保JSON数组中的元素与我们的存储库中的相应对象匹配。

我尝试了什么:

val response = response.entity.asString // Spray's way of getting the JSON response
repository.all.map { obj =>
  resp must */ ("id" -> obj.id)
  resp must */ ("state" -> generateState(obj)
}

问题是* / matcher只是发现“状态”:“无论什么”(假设generateState返回“what”)存在于JSON文档的某个地方,不一定是在与ID匹配的同一个

我尝试使用索引,但repository.all方法并不总是以相同的顺序返回元素,因此无法通过索引进行匹配。

我想要做的是,迭代JSON数组的元素并分别匹配每个元素。说一个/ ##运算符(或其他东西),它为每个元素提供匹配器:

resp /## { elem =>
  val id = elem("id")
  val obj = repository.lookup(id)
  elem /("state" -> generateState(obj))
}

有没有人有办法做到这一点或类似的东西?

2 个答案:

答案 0 :(得分:1)

现在可能最容易做的事情(直到JsonMatchers的严重重构)是进行一些解析并递归地使用JsonMatchers中的Matcher[String]

"""{'db' : { 'id' : '1', 'state' : 'ok_1'} }""" must /("db" -> stateIsOk)

// a string matcher for the json string in 'db'
def stateIsOk: Matcher[String] = { json: String =>
  // you need to provide a way to access the 'id' field
  // then you can go on using a json matcher for the state
  findId(json) must beSome { id: String =>
    val obj = repository.lookup(id)
    json must /("state" -> generate(obj))
  }
}

// I am using my own parse function here
def findId(json: String): Option[String] = 
  parse(json).flatMap { a => 
    findDeep("id", a).collect { case JSONArray(List(v)) => v.toString }
  }

// dummy system
def generate(id: String) = "ok_"+id

case object repository {
  def lookup(id: String) = id
}

答案 1 :(得分:0)

我最后做的是使用responseAs[JArray]JArray#arrJObject#values将JSON结构转换为ListMap s,然后使用标准的ListMap匹配器。更加灵活。