Обновление карты в рамке Groovy Spock - PullRequest
0 голосов
/ 24 сентября 2019

У меня есть спецификация спока ниже, и я хочу обновить карту из таблицы данных.Может ли какое-то тело помочь достичь этого

def "groovy map update"() {                                                   
        setup: "step1"                                                            

        Map json = [                                                              
                user :[                                                           
                        name : 'ABC'                                              
                ]]                                                                

        when: "step2"                                                             

        println ('Before modification:')                                          
        println (json)                                                            

        then: "step3"                                                             

        json.with {                                                               
            //user.name = value // this one works                                 
            (field) = value   // this one does not work                           
        }                                                                         

        println ('After modification:')                                           
        println (json)                                                            

        where:                                                                    
        field                               | value                               
        'user.name'                         | 'XYZ'                               

    }   

Ответы [ 2 ]

2 голосов
/ 25 сентября 2019

Принятое решение верное, я просто хочу показать альтернативу, которая делает то же самое немного другим способом, предполагая, что вы хотите придерживаться пунктирной записи для field в вашем блоке where:.Я просто добавил еще два тестовых случая, чтобы убедиться, что он работает должным образом.

@Unroll
def "set #field to #value"() {
  setup: 'create json'
  Map json = [user: [name: 'ABC', address: [street: '21 Main St', zip: '12345', city: 'Hometown']]]

  when: 'update it'
  def subMap = json
  field.split("[.]").each {
    if (subMap[it] instanceof Map)
      subMap = subMap[it]
    else
      subMap[it] = value
  }
  println json

  then: 'check the assignment'
  json.newField == value ||
    json.user.name == value ||
    json.user.address.zip == value

  where:
  field              | value
  'newField'         | 'dummy'
  'user.name'        | 'XYZ'
  'user.address.zip' | '98765'
}

Обновление: Если вы хотите сохранить несколько строк кода, вы также можетеиспользуйте операцию сгиба (или уменьшения или накопления) с помощью inject(..), как описано здесь

@Unroll
def "set #field to #value"() {
  setup: 'create json'
  Map json = [user: [name: 'ABC', address: [street: '21 Main St', zip: '12345', city: 'Hometown']]]

  when: 'update it'
  field.split("[.]").inject(json) { subMap, key ->
    subMap[key] instanceof Map ? subMap[key] : subMap.put(key, value)
  }
  println json

  then: 'check the assignment'
  json.newField == value ||
    json.user.name == value ||
    json.user.address.zip == value

  where:
  field              | value
  'newField'         | 'dummy'
  'user.name'        | 'XYZ'
  'user.address.zip' | '98765'
}

Считаете ли вы, что это читается или нет, может зависеть от вашего знакомства с такими темами, как функциональное программирование ввообще или карта / уменьшить в частности.Прелесть здесь, в дополнение к краткости, заключается в том, что нам больше не нужна локальная переменная вне нашего замыкания, а мы просто внедряем (отсюда и название метода) результат итерации n в итерацию n + 1.

Кстати, какхороший побочный эффект inject(..), поскольку я использую его здесь, возвращает предыдущее значение значения, которое вы установили или перезаписали.Просто добавьте println перед field.split("[.]").inject(json) ..., чтобы увидеть его.


Обновление 2: Обратите внимание, что оба варианта работают, только если не существует существующего значения полявведите Map в поле назначения из-за instanceof Map проверки эвристики в моем коде.Т.е. эти два случая не будут работать:

    'user.address'            | [street: '23 Test Blvd', zip: '33333', city: 'Somewhere']
    'user.address'            | '23 Test Blvd, 33333 Somewhere'

Этот вариант будет работать, хотя, потому что нет никакого ранее существующего значения:

    'user.alternativeAddress' | [street: '23 Test Blvd', zip: '33333', city: 'Somewhere']
2 голосов
/ 24 сентября 2019

Раздел then предназначен для утверждений, а не для обновлений и т. Д. Поэтому необходимо обновить карту в разделе when, а затем проверить результат в разделе then.Например, вот так:

def "groovy map update"() {
    setup: 'create json'
    Map json = [user: [name: 'ABC']]

    when: 'update it'
    def target = json
    for (node in path - path.last()) {
        target = target[node]
    }
    target[path.last()] = value

    then: 'check the assignment'
    json.user.name == value

    where:
    path             | value
    ['user', 'name'] | 'XYZ'
}

Одним из способов обновления вложенного значения Map может быть использование списка узлов пути вместо нотации поля, а затем итерация по ним для получения последнего экземпляра Map иустановите значение там:

def target = json
for (node in path - path.last()) {
    target = target[node]
}
target[path.last()] = value
...