4

我需要为用 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 更改只需修改构建器功能和后端以适应我的测试用例。

这是解决问题的可能/有效方法吗?创建这样的语法树有什么更好的想法吗?

谢谢!

——马蒂亚斯。

4

1 回答 1

1

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

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

创建这种可扩展 AST 的全功能方法是使用点菜数据类型技术。简而言之,您定义了一个通用的“sum”类型运算符,然后构建对递归类型的某些组件总和进行操作的函数。通过巧妙的默认设置,您可以省略许多样板定义并允许可扩展性。

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

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

于 2013-07-26T14:22:09.983 回答