使用Spock数据表填充对象

7

我第一次使用Spock。由于我们正在使用复杂的领域模型,因此最好有一种机制,可以允许我根据由Spock表给出的数据创建完整对象。我不想每次都给出所有值,我只想在数据表中定义的值。因此,应该在某个地方定义默认值。

是的,我知道我可以自己编写代码,但也许有现成的解决方案。

示例

class A {
   String name
   int age
}

Spock表

id | givenA                     | ...
1  | [name: "Michael"]          | ...
2  | [name: "Thomas", age: 45 ] | ...
  1. => A.name = "Michael",A.age = 在某处定义的默认值
  2. => A.name = "Thomas",A.age = 45(因为我覆盖了默认值)

1
@Opal:忘记在行末加上“;”是一件很麻烦的事情。感谢您将其删除 :-) - EhmKah a.k.a. Michael Krauße
是的,开始总是困难的 ;) - Opal
3个回答

17

在我每个项目中,我都会创建一个我称之为“UnitTestUtils”的类,这个类主要包含一些帮助方法,可以使用默认值创建领域对象,并允许对这些值进行覆盖。例如:

    Person createTestPerson(Map overrides = [:]){
        Person p = new Person(name: "Jim Bob", age: 45)
        overrides.each { String key, value ->
            if(p.hasProperty(key)){
                p.setProperty(key, value)
            } else {
                println "Error: Trying to add property that doesn't exist"
            }
        }
        return p
    }

然后,您可以通过以与已经完成的方式创建映射来在类中使用此方法。

    void "my test"(){
        given:
            Person person
        when:
            person = UnitTestUtils.createTestPerson(givenA)
        then:
            person.name == expected.name
            person.age == expected.age
        where:
          id| givenA        | expected
          1 | [name: "Joe"] | [name: "Joe", age: 45]
          2 | [age: 5]      | [name: "Jim Bob", age: 5]
    }

这不是Spock的内置功能,但它应该很好地满足您指定的用例。


我对Groovy很新。此解决方案将自动覆盖每个字段。我不需要为新属性扩展它吗? - EhmKah a.k.a. Michael Krauße
在我的例子中,每次调用“createTestPerson(givenA)”时,您将创建一个新的Person对象。将givenA传递给该方法,并提供与对象字段名称匹配的键/值对,将简单地使用映射中指定的值替换任何指定的字段。由于您只是将映射传递给返回Person的方法,因此无需扩展任何内容。 - th3morg
此外,@EhmKa,你可以使用Map而不是类,它会产生相同的效果。 - th3morg

1
基本上没有您正在寻找的机制。如果您需要为某些对象/字段提供默认值,则需要自行完成,这并不奇怪,不好或不寻常。请记住,测试代码的质量与生产代码同样重要,创建一些仅用于测试的助手代码并不是不好的做法(当然,此代码仅存在于测试层次结构中)。
在这种特殊情况下,您可以使用Map.withDefault构造而不是创建A类,但是我认为使用专用类更好。

真遗憾。但我必须与Spock进行一些实验,以找到一个好的交易。我已经编写了一些工厂,使用映射来创建完整的领域对象。 - EhmKah a.k.a. Michael Krauße
我不是很了解具体情况,但经过思考,我认为一个简单的映射可能会是最有力的。如果您对答案感到满意,请接受它。 - Opal

0

不确定你具体想要什么,但是你可以写成 new A(name: Thomas, age: 45) 而非 [name: "Thomas", age: 45]。如果你想要重复使用测试数据,也可以这样做:

where:
[id, givenA] << staticUtilityMethodThatReturnsCollectionOfTwoElementCollections()

您还可以创建一个小的 API(或使用 Groovy 的内置集合操作)来修改默认值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接