2014-10-02 104 views
4

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

是的,我知道我可以自己写,但也许有一个开箱即用的解决方案。

class A { 
    String name 
    int age 
} 

斯波克表

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

@Opal:忘记“;”的方法很长。在一行的结尾。谢谢你删除它:-) – EhmKah 2014-10-02 09:09:32

+0

是的,开始总是很难;) – Opal 2014-10-02 09:53:04

回答

10

在每个项目中,我创建了我称之为“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功能,但它应该很好地为您指定的用例提供。

+0

我对groovy很陌生。该解决方案将自动覆盖每个字段。我不需要将它扩展为新的属性? – EhmKah 2014-10-15 19:41:30

+0

在我的示例中,您将创建一个新的Person对象,每次调用“createTestPerson(givenA)”。将givenA传递给方法并提供匹配对象字段名称的键/值对将简单地将地图中指定的任何字段替换为地图中指定的值。你不需要扩展任何东西,因为你只是将地图传递给返回Person的方法。 – th3morg 2014-10-15 20:39:16

+0

此外,@EhmKa,而不是使用一个类,你可以只使用一个地图。它会有同样的效果。 – th3morg 2014-10-16 16:44:42

1

基本上没有这样的机制,你正在寻找。如果您需要为某些对象/字段提供默认值您需要自己做,并且没有什么奇怪的,不好的或不寻常的。请记住,测试代码的质量与生产代码一样重要,创建仅用于测试的代码(当然,此代码仅存在于测试层次结构中)创建一些帮助程序并不是一个坏习惯。

在这种特殊情况下,而不是创建A类您可以使用Map.withDefault构造,但使用专用类的IMO要好得多。

+0

太可惜了。但我必须用spock做一些实验才能找到一个好的交易。我已经写了一些工厂,它们使用地图来创建完整的域对象。 – EhmKah 2014-10-02 09:11:02

+0

我不太了解情况,但经过一番思考后,我猜想一个简单的地图将是最强大的。如果您对答案感到满意,请接受它。 – Opal 2014-10-02 09:54:43

0

不知道你到底在找什么,而不是[name: "Thomas", age: 45],你可以写new A(name: Thomas, age: 45)。如果你想重新使用夹具,你可以这样做:

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

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

1

为什么不使用Builder图案?您可以提供一种方法,该方法将创建具有默认值的具体A对象,例如

A.builder() 
    .withDefaults(HereAreDefaultValues.class) 
    .withName('Michael') 
    .build() 

此示例使用单独的类,用于存储默认值,它应该在构建整备区复制所有这些属性。你也可以使用Map来做到这一点。

在这种情况下,任何稍后会读取您的测试的人都将能够检查默认值是什么,并且如果测试将在这些默认值发生更改时失败,将不会感到惊讶。你应该避免隐藏细节,比如队友(或者你自己)的默认值,因为这会让你的测试非常难以维护。 生成器示例更详细,我知道,但它作为软件的工件肯定更有用。

+0

因为与Spock提供的漂亮的数据表机制相比,即使构建器也过于冗长。不幸的是,从1.0开始,Spock只允许将这些参数用于参数化测试运行,而不是在此之外建立设置数据。 – Pavel 2015-08-19 09:55:21