Frage

I'm using the Specs2 JSONMatcher to validate that a GET request is being correctly converted from its internal representation (there are some manipulations we do before generating the JSON). What I need to do is, make sure that an element in the JSON array matches the corresponding object from our repository.

What I've tried:

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)
}

The problem is that the */ matcher just finds that "state": "whatever" (assuming generateState returns "whatever") exists somewhere in the JSON document, not necessarily in the same one matched by the ID

I tried using the indices but the repository.all method doesn't always return the elements in the same order, so there's no way of matching by index.

What I'd like to do is, iterate over the elements of the JSON array and match each one separately. Say an /## operator (or something) that takes matchers for each element:

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

Does anyone have a way to do this or something similar?

War es hilfreich?

Lösung

Probably the easiest thing to do for now (until a serious refactoring of JsonMatchers) is to do some parsing and recursively use a JsonMatchers in a 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
}

Andere Tipps

What I did in the end is use responseAs[JArray], JArray#arr and JObject#values to convert the JSON structures into Lists and Maps, and then used the standard List and Map matchers. Much more flexible.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top