Kotest JSON 매처(JSON Matchers)

JSON 매처에 대해서 설명한다.

개요

Json 매처를 사용하려면 빌드에 testImplementation("io.kotest.extensions:kotest-assertions-json:<version>")을 추가해야 한다.

기본 매처

매처 설명 대상
shouldBeValidJson 주어진 문자열이 유효한 json으로 구문 파싱이 되는지 확인한다. Multiplatform
shouldBeJsonObject 문자열이 유효한 JSON 객체인지 확인한다. Multiplatform
shouldBeJsonArray 문자열이 유효한 JSON 배열인지 확인한다. Multiplatform

콘텐츠 기반 매칭

자세한 내용은 JSON 콘텐츠 매칭를 참조한다.

매처 설명 대상
shouldEqualJson 문자열이 지정된 JSON 구조와 일치하는지 확인한다. Multiplatform
shouldEqualSpecifiedJson 문자열이 지정된 JSON 구조와 일치하는지 확인하지만 지정되지 않은 추가 속성을 허용한다. Multiplatform
shouldContainJsonKey 문자열이 JSON이고 지정된 JSON 경로를 포함하는지 확인한다. JVM
shouldContainJsonKeyValue 문자열이 JSON이고 지정된 값을 가진 지정된 JSON 경로를 포함하는지 확인한다. JVM
shouldMatchJsonResource 문자열이 지정된 테스트 리소스의 JSON 콘텐츠와 일치하는지 확인한다. JVM

스키마 검증

매처 설명 대상
shouldMatchSchema String 또는 kotlinx.serialization.JsonElement가 JsonSchema와 일치하는지 확인한다. 스키마 구성에 대한 자세한 내용은 아래 설명을 참조한다. Multiplatform

JSON 콘텐츠 매칭

이 모듈은 JVM 및 JS 대상에 사용할 수 있다.

shouldEqualJson

json.shouldEqualJson(other)은 왼쪽이 오른쪽과 동일한 JSON 구조와 동일한지 확인한다.

이 매처는 다른 형식과 다른 키 순서를 허용한다.

예를 들어, 다음 두 개의 JSON 문자열은 동일한 것으로 간주된다:

{
   "name": "sam",
   "location": "chicago",
   "age" : 41
}

그리고

{ "age" : 41, "name": "sam", "location": "chicago" }

이 매처의 반대는 shouldNotEqualJson으로, 두 개의 JSON 문자열이 동일한 것으로 간주되면 오류가 발생한다.

compareJsonOptions

shouldEqualJson은 JSON 비교의 동작을 토글하기 위해 다음 플래그를 지원하는 CompareJsonOptions 유형의 추가 매개 변수를 지원한다:

사용법:
옵션은 다음과 같이 인라인(inline)으로 지정할 수 있다.

a.shouldEqualJson(b, compareJsonOptions { arrayOrder = ArrayOrder.Strict })

또 다른 옵션은 다음과 같이 원하는 대로 비교 기능을 정의하는 것이다:

val myOptions = compareJsonOptions {
   typeCoercion = TypeCoercion.Enabled
   arrayOrder = ArrayOrder.Lenient
}

infix fun String.lenientShouldEqualJson(other: String) = this.shouldEqualJson(other, myOptions)

"[1, 2]" lenientShouldEqualJson "[2, 1]" // This will pass
Parameters
이름 목적 가능한 값 기본값
PropertyOrder 비교할 때 JSON 개체의 속성 순서를 고려하는지 결정한다. PropertyOrder.Strict, PropertyOrder.Lenient PropertyOrder.Lenient, 속성의 순서는 중요하지 않다.
ArrayOrder 비교할 때 JSON 배열의 요소 순서가 고려되는지 결정한다. ArrayOrder.Strict, ArrayOrder.Lenient ArrayOrder.Strict, 요소의 순서가 중요하다.
FieldComparison JSON 객체에 actualJSONexpected과 비교했을 때, 추가 속성이 실제로 포함되어 있는 경우 비교가 실패할지 여부를 결정한다. FieldComparison.Strict, FieldComparison.Lenient FieldComparison.Strict, 추가 속성으로 인해 불평등이 발생한다.
NumberFormat 숫자 형식과 관련하여 숫자 비교가 엄격한지 여부를 결정한다. 예를 들어 100.0과 100이 동일한 것으로 간주되는 경우이다. NumberFormat.Strict, NumberFormat.Lenient NumberFormat.Lenient, 숫자 형식은 중요하지 않다.
TypeCoercion 예를 들어 문자열에 숫자나 부울 값이 포함된 경우 유형을 강제로 적용할지 여부를 결정한다. TypeCoercion.Enabled, TypeCoercion.Disabled TypeCoercion.Disabled, 유형은 강제되지 않는다.

대상: Multiplatform

shouldEqualSpecifiedJson

shouldEqualJson의 별칭으로, 기본 옵션은 FieldComparison을 제외하고 대신에 FieldComparison.Lenient로 설정된다.

val a = """ { "a": true, "date": "2019-11-03" } """
val b = """ { "a": true } """

// this would pass
a shouldEqualSpecifiedJson b

// this would fail
a shouldEqualJson b

대상: Multiplatform

shouldContainJsonKey

json.shouldContainJsonKey("$.json.path")는 JSON 문자열에 지정된 JSON 경로가 포함되어 있는지 확인한다.

이 매처의 반대는 shouldNotContainJsonKey로, JSON 문자열에 지정된 JSON 경로가 포함되어 있으면 오류가 발생한다.

대상: JVM

shouldContainJsonKeyValue

str.shouldContainJsonKeyValue("$.json.path", value)는 JSON 문자열에 특정 값을 가진 JSON 경로가 포함되어 있는지 확인한다.

이 매처의 반대는 shouldNotContainJsonKeyValue로, JSON 문자열에 지정된 JSON 경로에 지정된 값이 포함되어 있으면 오류가 발생한다.

대상: JVM

shouldMatchJsonResource

json.shouldMatchJsonResource("/file.json")는 속성의 순서와 서식을 무시하고 JSON이 기존 테스트 리소스 /file.json과 같은지 확인한다.

대상: JVM

JSON 스키마 매처

매처 설명 대상
shouldMatchSchema String 또는 kotlinx.serialization.JsonElement가 JsonSchema와 일치하는지 확인한다. 스키마 구성에 대한 자세한 내용은 아래 설명을 참조한다. Multiplatform

JSON 스키마의 하위 집합은 텍스트 스키마를 파싱하여 정의할 수 있다.

예시:

val parsedSchema = parseSchema(
  """
  {
  "$id": "https://example.com/geographical-location.schema.json",  // will  be ignored
  "$schema": "https://json-schema.org/draft/2020-12/schema",       // will be ignored
  "title": "Longitude and Latitude Values",                        // will be ignored
  "description": "A geographical coordinate.",                     // will be ignored
  "required": [ "latitude", "longitude" ],
  "type": "object",
  "properties": {
    "latitude": {
      "type": "number",
      "minimum": -90,
      "maximum": 90
    },
    "longitude": {
      "type": "number",
      "minimum": -180,
      "maximum": 180
    }
  }
}
  """
)

또는 Kotest의 내장 DSL을 사용한다:

val addressSchema = jsonSchema {
  obj {   // object is reserved, obj was chosen over jsonObject for brevity but could be changed ofc, or jsonObject could be added as alternative.
    withProperty("street", required = true) { string() }
    withProperty("zipCode", required = true) {
      integer {
        beEven() and beInRange(10000..99999)   // supports constructing a matcher that will be used to test values
      }
    }
    additionalProperties = false   // triggers failure if other properties are defined in actual
  }
}

val personSchema = jsonSchema {
  obj {
    withProperty("name", required = true) { string() }
    withProperty("address") { addressSchema() } // Schemas can re-use other schemas 🎉
  }
}

스키마 구축

배열

배열은 정렬된 요소에 사용된다. JSON에서 배열의 각 요소는 다른 유형일 수 있다.

Length (minItems and maxItems)

배열의 길이는 minItemsmaxItems 키워드를 사용하여 지정할 수 있다. 각 키워드의 값은 음수가 아닌 숫자이어야 하며 기본값은 0과 Int.MAX_VALUE이다.

val lengthBoundedSchema = jsonSchema {
  array(minItems = 0, maxItems = 1) { number() }
}
Uniqueness

스키마는 배열의 각 항목이 고유한지 확인할 수 있다. uniqueItems 키워드를 true로 설정하기만 하면 된다.

val uniqueArray = jsonSchema {
  array(uniqueItems = true) { number() }
}

⚠️ Kotest는 현재 JSON 스키마의 하위 집합만 지원한다. 현재 지원되지 않는 항목은 다음과 같다:

  • $defs and $refs
  • Recursive schemas
  • Parsing of schema composition
  • string.format
  • array.prefixItems,
  • array.contains,
  • array.items = false
  • array.maxContains
  • array.minContains
  • array.uniqueItems
  • enum

검증

스키마가 정의되면 이를 기준으로 Stringkotlinx.serialization.JsonElement의 유효성을 검사할 수 있다:

"{}" shouldMatchSchema personSchema

// fails with:
// $.name => Expected string, but was undefined

""" { "name": "Emil", "age": 34 } """
// Passes, since address isn't required and `additionalProperties` are allowed

참조




최종 수정 : 2024-04-24