实现构建器模式以在haskell中生成测试用例

时间:2013-07-26 08:24:59

标签: haskell code-generation

我需要为用Java编写的应用程序生成黄瓜测试用例。

测试用例如下:

Scenario My great test
    Given the following input
        """
            Code snippet of a DSL
        """
    And the following data
        | name | type    | value |
        |    a | Boolean |  true |
        |    b | Integer |     5 |
    When I run the evaluation
    Then the result should be "Yay!"

我创建了类似于这种结构的数据类型作为语法树以及一个“后端”,它将采用语法树并创建测试用例字符串。

数据类型如下:

data TestCase = Scenario String DslStatement DataStatement ResultStatement

data DslStatement = Dsl [TopLevelStatement]

data TopLevelStatement =
    StatementTypeA String
  | StatementTypeB String
  | StatementTypeC String SubStatementTypeA [SubStatementTypeB]
  | StatementTypeD String [String]

...

等等。

现在我想使用不同的值和类型以及内容生成大量的这些数据结构。

我可以编写带有必要参数的函数,并创建一个语法树,其中的参数值应该出现在它们应该出现的位置。但是,由于测试用例中包含的DSL一直在变化(它是逐步开发的),我将不得不改变所有创建不同测试用例类型的函数,这很乏味。此外,测试用例可以基于标准语法树,只在少数几个测试用例的地方修改。

我现在的想法是创建或多或少类似于Java中具有流畅界面的构建器模式的函数。从标准语法树开始,我创建了修改它的函数,并返回结果树以进行进一步修改,如下所示:

withName :: String -> TestCase -> TestCase
withName name (Scenario _ dsl data result) = Scenario name dsl data result

withResult :: ResultStatement -> TestCase -> TestCase
withResult result (Scenario name dsl data _) = Scenario name dsl data result

...

然后我应该能写出这样的东西:

withName "My Test Case" . withResult (Result "Yay!") $ createStandardTestCase

只要dsl更改,只需要修改构建器函数和后端,以便调整我的测试用例。

这是解决问题的可行/有效方法吗? 有没有更好的创建这种语法树的想法?

THX!

- 的Mathias

1 个答案:

答案 0 :(得分:1)

在Haskell中,流畅的接口模式称为Endo。它是Monoid,因此您可以使用mconcat获得一些效率,但我很少看到Endo在实践中使用,因为它不是一个巨大的收获。

对于这样的定义,您将面临的一个挑战是需要默认的所有内容,毕竟withName "My Test Case"本身需要一个有效的TestCase。这可能意味着您的许多类型将是Maybe或者它可能只是意味着您需要仔细定义类型。这可能与您的标准语法树的概念有关。

创建这种可扩展AST的全功能方法是使用Data types a la carte技术。简而言之,您定义了一个通用的“sum”类型运算符,然后构建了对递归类型的某些组件进行操作的函数。通过具有聪明的默认值,您可以省略许多样板定义并允许可扩展性。

此类技术可能对您的类型有用。

最后,很难谈论像这样的嵌套数据类型,而不是通过Control.Lens(包括所有可能的电池)或fc-labels(更简单)来讨论透镜的建议。这些让您可以对您的树进行深入检查,可以双向使用,以查看和构建更新Endo。它们还具有聪明的通用原则,例如能够同时“关注”树中的多个位置(这些是Fold中的TraversalControl.Lens。)

相关问题