条约:需要非空映射(或非空字段)的匹配规则

时间:2018-07-25 16:22:13

标签: pact pact-jvm pact-java

在使用pact-jvm(https://github.com/DiUS/pact-jvm)编写消费者契约时,我需要帮助。

我的问题是我有一个字段,它是地图的列表(数组)。每个地图可以具有不同类型的元素(字符串或子地图),例如

"validatedAnswers": [
    {
      "type": "typeA",
      "answers": {
        "favourite_colour": "Blue",
        "correspondence_address": {
            "line_1": "Main St",
            "postcode": "1A 2BC",
            "town": "London"
        }
      }
    },
    {
      "type": "typeB",
      "answers": {
        "first_name": "Firstname",
        "last_name": "Lastname",
      }
    }
  ]

但是我们只对其中一些答案感兴趣。

注意:上面仅是显示validatedAnswers的结构的示例。每个answers映射都有数十个元素。

我们真正需要的是:https://github.com/pact-foundation/pact-specification/issues/38,但计划在v.4中使用。同时,我们正在尝试另一种方法。我现在想要做的是指定列表中的每个元素都是一个非空映射。另一种方法是指定列表的每个元素都不为空。可以使用Groovy DSL来完成这一切吗?

此:

new PactBuilder().serviceConsumer('A').hasPactWith('B')
.port(findAvailablePort()).uponReceiving(...)
.willRespondWith(status: 200, headers: ['Content-Type': 'application/json'])
.withBody {
  validatedAnswers minLike(1) {
     type string()
     answers {
     }
  }
}

不起作用,因为它意味着answers应该为空(“预期为空的Map但收到了Map([...])”,另请参见https://github.com/DiUS/pact-jvm/issues/298)。

所以我想做的是这样的:

.withBody {
    validatedAnswers minLike(1) {
         type string()
         answers Matchers.map()
    }
}

或:

validatedAnswers minLike(1) {
     type string()
     answers {
             keyLike 'title', notNull()
     }
}

或:

validatedAnswers minLike(1) {
     type string()
     answers notNull()
}

能做到吗?

2 个答案:

答案 0 :(得分:1)

为此,我将创建两个独立的测试,一个针对每个不同响应形状的测试,并为每个响应形状提供一个提供者状态,例如given there are type b answers

这样,当您在提供方进行验证时,它只会发送这两种字段类型。

两个示例的并集给出了允许两者的契约。

答案 1 :(得分:0)

您可以在没有DSL的情况下进行操作,请使用示例Groovy脚本:

class ValidateAnswers {
    static main(args) {
        /* Array with some samples */
        List<Map> answersList = [
            [
                type: 'typeA',
                answers: [
                    favourite_colour: 'Blue',
                    correspondence_address: [
                        line_1: 'Main St',
                        postcode: '1A 2BC',
                        town: 'London'
                    ]
                ]
            ],
            [
                type: 'typeB',
                answers: [
                    first_name: 'Firstname',
                    last_name: "Lastname"
                ]
            ],
            [
                type: 'typeC',
                answers: null
            ],
            [
                type: 'typeD'
            ],
            [
                type: 'typeE',
                answers: [:]
            ]
        ]

        /* Iterating through all elements in list above */
        for (answer in answersList) {
            /* Print result of checking */
            println "$answer.type is ${validAnswer(answer) ? 'valid' : 'not valid'}"
        }
    }

    /**
    * Method to recursive iterate through Map's.
    * return true only if value is not an empty Map and it key is 'answer'.
    */
    static Boolean validAnswer(Map map, Boolean result = false) {
        map.each { key, value ->
            if (key == 'answers') {
                result = value instanceof Map && value.size() > 0
            } else if (value instanceof Map) {
                validAnswer(value as Map, false)
            }
        }

        return result
    }
}

输出为:

typeA is valid
typeB is valid
typeC is not valid
typeD is not valid
typeE is not valid