在 groovy spock 框架中更新地图
Update a Map in groovy spock framework
我有以下 spock 规范,想根据数据 table 更新地图。有人可以帮助实现这个吗
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'
}
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
接受的解决方案是正确的,我只是想展示一个以稍微不同的方式做同样事情的替代方案,假设你想在你的 where:
块中坚持使用 field
的点分符号.我刚刚添加了两个测试用例以确保它按预期工作。
@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(..)
使用折叠(或减少或累积)操作,如所述 here
@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'
}
您是否觉得可读性可能取决于您对函数式编程等主题的熟悉程度,尤其是 map/reduce。除了简洁之外,这里的魅力在于我们不再需要闭包之外的局部变量,而我们只需将迭代 n 的结果注入(因此称为方法名称)到迭代 n+1。
顺便说一句,作为一个很好的副作用 inject(..)
因为我在这里使用它 returns 您设置或覆盖的值的先前值。只需在 field.split("[.]").inject(json) ...
前添加 println
即可看到。
更新 2: 请注意,由于 instanceof Map
检查我的代码中的启发式方法。 IE。这两种情况都行不通:
'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']
我有以下 spock 规范,想根据数据 table 更新地图。有人可以帮助实现这个吗
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'
}
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
接受的解决方案是正确的,我只是想展示一个以稍微不同的方式做同样事情的替代方案,假设你想在你的 where:
块中坚持使用 field
的点分符号.我刚刚添加了两个测试用例以确保它按预期工作。
@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(..)
使用折叠(或减少或累积)操作,如所述 here
@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'
}
您是否觉得可读性可能取决于您对函数式编程等主题的熟悉程度,尤其是 map/reduce。除了简洁之外,这里的魅力在于我们不再需要闭包之外的局部变量,而我们只需将迭代 n 的结果注入(因此称为方法名称)到迭代 n+1。
顺便说一句,作为一个很好的副作用 inject(..)
因为我在这里使用它 returns 您设置或覆盖的值的先前值。只需在 field.split("[.]").inject(json) ...
前添加 println
即可看到。
更新 2: 请注意,由于 instanceof Map
检查我的代码中的启发式方法。 IE。这两种情况都行不通:
'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']