2013-07-26 2 views
4

Мне нужно сгенерировать тестовые примеры огурцов для приложения, написанного на Java.Реализация шаблона построителя для генерации тестовых примеров в haskell

Тестовый пример будет выглядеть так:

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.

+0

Я написал сообщение некоторое время назад о свободном интерфейсе для строителей [в этом посте] (http://www.haskellforall.com/2013/02/you-could-have-invented-comonads.html). Это близко к тому, что вы имели в виду? –

ответ

1

Свободный шаблон интерфейса называется Endo в Haskell. Это Monoid, поэтому вы можете получить некоторую эффективность, используя mconcat, хотя я редко вижу, что Endo используется на практике, так как это не огромный выигрыш.

Один вызов, с которым вы столкнетесь с таким определением, - это необходимость в настройках по умолчанию, ведь withName "My Test Case" должен быть действительным TestCase сам по себе. Это может означать, что многие из ваших типов будут Maybe s, или это может означать, что вы хотите тщательного определения ваших типов. Это может быть связано с вашим представлением о стандартном дереве синтаксиса.

Полностью приведенный в действие метод создания такого расширяемого АСТ заключается в использовании методов Data types a la carte. Короче говоря, вы определяете общий оператор типа «сумма», а затем строите функции, которые работают с некоторой суммой компонентов вашего рекурсивного типа. Благодаря умным значениям по умолчанию вы можете опустить многие, многие описания шаблонов и допускать расширяемость.

Такие методы могут быть полезны для ваших типов.

Наконец, трудно говорить о вложенных типах данных, таких как это, не бросая предложение посмотреть линзы либо через Control.Lens (каждая возможная батарея включена), либо fc-labels (проще). Это позволяет делать глубокие проверки в ваших деревьях, которые можно использовать в двух направлениях, как для просмотра, так и для сборки обновлений Endo. У них также есть умные общие принципы, такие как возможность «сосредоточиться» на нескольких местоположениях на вашем дереве одновременно (это Fold и Traversal с в Control.Lens).

Смежные вопросы