DSL生成测试数据

时间:2010-04-13 11:54:18

标签: unit-testing antlr dsl

有多种方法可以为测试生成数据(不仅仅是单元测试),例如,Object Mother,构建器等。另一种有用的方法是将测试数据写为纯文本:

product: Main; prices: 145, 255; Expire: 10-Apr-2011; qty: 2; includes: Sub
product: Sub; prices: 145, 255; Expire: 10-Apr-2011; qty: 2

然后将其解析为C#对象。这在单元测试中很容易使用(因为深层内部集合可以用单行编写),这在类似FitNesse的系统中使用起来更加方便(因为这个DSL自然适合wiki),等等。

所以我使用它并编写解析器,但每次编写都很繁琐。我不是DSL /语言解析器的大专家,但我认为他们可以在这里提供帮助。什么是正确的使用?我只听说过:

  • DSL(我的意思是,任何 DSL)
  • Boo(我认为可以做DSL)
  • ANTLR

但我甚至不知道选择哪一个以及从哪里开始。

所以问题是:使用某种DSL生成测试数据是否合理?你有什么建议吗?有没有现有案例?

更新:好像我不够清楚。它不是关于原始字符串到对象转换。查看第一行并将其与

联系起来
var main = Product.New("Main")
   .AddPrice(Price.New(145).WithType(PriceType.Main).AndQty(2))
   .AddPrice(Price.New(255).WithType(PriceType.Maintenance).AndQty(2))
   .Expiration(new DateTime(10, 04, 2011));
var sub =  Product
   .New("Sub").Parent(main)
   .AddPrice(...));
main.AddSubProduct(sub);
products.Add(main);
products.Add(sub);

请注意,我首先创建子产品,然后将其添加到main,即使它以相反的顺序列出。价格以特殊方式处理。我想指定Sub产品的名称并获得它的引用 - 创建。我想在单行上列出所有产品属性 - FLAT和NON-REPEATATIVE。我想使用属性的默认值。等等。

更新:我不相信避免使用DSL,因为所有替代示例都过于冗长且不便于用户使用。没有人说过有关DSL的任何有用的东西。

3 个答案:

答案 0 :(得分:2)

对于数据DSL YAML是一个很好的候选人。以下是维基百科的样本:

---
receipt:     Oz-Ware Purchase Invoice
date:        2007-08-06
customer:
    given:   Dorothy
    family:  Gale

items:
    - part_no:   A4786
      descrip:   Water Bucket (Filled)
      price:     1.47
      quantity:  4

    - part_no:   E1628
      descrip:   High Heeled "Ruby" Slippers
      price:     100.27
      quantity:  1

bill-to:  &id001
    street: |
            123 Tornado Alley
            Suite 16
    city:   East Westville
    state:  KS

ship-to:  *id001

specialDelivery:  >
    Follow the Yellow Brick
    Road to the Emerald City.
    Pay no attention to the
    man behind the curtain.

我在几个项目中使用YAML并对此感到满意。

但是,如果我们讨论的是单元 - 测试,那么使用构造函数和属性赋值就地“手动”构造必要的对象通常更简单,更具可读性。这是因为单元测试本质上高度集中在一些代码(单元)上,并且创建足够 的数据基础设施并不难以进行测试。在单元测试中对半完全实体进行操作是可以的,不必费心构建与此具体测试无关的数据。

对于功能测试,YAML很棒。

答案 1 :(得分:1)

我首先要看看我选择的语言是否足以构建我的DSL。 C#应该很容易处理你的情况:

Product[] products = new Product[] {
    new TestProduct{product="Main", prices=new[]{145, 255}, Expire="10-Apr-2011", qty=2, includes="Sub"},
    new TestProduct{product="Sub", prices=new[]{145, 255}, Expire="10-Apr-2011", qty=2}
};

不是那么漂亮,但肯定可以容忍,我很难证明自定义DSL的额外努力是合理的。

另请注意,Expire初始化为字符串,但显然是日期。这对于DSL习语来说是完全合理的,因为TestProduct.Expire的setter可以进行翻译。

答案 2 :(得分:0)

对于创建外部DSL,我建议Eclipse TMF Xtext非常好(基于ANTLR但更简单),但是建立在Eclipse和Java之上,但是您可以生成任何代码。 在创建测试数据方面,我受到了Ruby on Rails人员的启发,这是另一个答案中提到的YAML灯具,但我也看到了一种使用工厂的方法,它可以帮助你摆脱一些两面性和不灵活性。看看这个Railscasts 158: Factories not Fixtures,它可能会给你一些设计DSL的想法。