Implementing a builder pattern for generating test cases in haskell

I need to generate test cases of cucumbers for an application written in Java.

An example test will look like this:

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!" 

I created data types that resemble this structure as a syntax tree, as well as a backend that will take a syntax tree and create a test case line.

Data types are as follows:

 data TestCase = Scenario String DslStatement DataStatement ResultStatement data DslStatement = Dsl [TopLevelStatement] data TopLevelStatement = StatementTypeA String | StatementTypeB String | StatementTypeC String SubStatementTypeA [SubStatementTypeB] | StatementTypeD String [String] ... 

etc.

Now I want to create many, many of these data structures using different values โ€‹โ€‹and types and so on.

I could write functions that take the necessary parameters and create a syntax tree with values โ€‹โ€‹from the parameters inserted in the locations that they should appear. However, since the DSL contained in the test case can be changed all the time (it develops gradually), I would have to change all the functions creating the different types of test cases all the time, which is tedious. In addition, test cases can be based on a standard syntax tree, which is modified in only a few places for most test cases.

Now my idea is to create functions that are more or less similar to what would be a designer template with a smooth interface in Java. Starting with the standard syntax tree, I create functions that modify this and return the resulting tree for further change as follows:

 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 ... 

Then I would have to write something like this:

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

and as soon as the dsl changes should only change the functions of the builder and backend to adapt my test cases.

Is this a possible / valid approach to the problem? Any better ideas for creating such syntax trees?

thanks!

-. Mathias

+4
source share
1 answer

The free interface template is called Endo in Haskell. This is a Monoid , so you can get some efficiency with mconcat , although I rarely see Endo used in practice, since it is not a huge gain.

One of the challenges you will encounter with such a definition is the need for default settings, because withName "My Test Case" must be a valid TestCase in itself. This may mean that many of your types will be Maybe , or it may mean that you need careful definitions of your types. This may be related to your understanding of the standard syntax tree.

The fully-powered method for creating such an extensible AST is to use a la carte data type methods. In short, you define a general โ€œsumโ€ operator, and then build functions that work with some sum of components of your recursive type. Thanks to smart defaults, you can omit many, many template descriptions and allow for extensibility.

Such methods may be useful for your types.

Finally, itโ€™s hard to talk about nested data types like this without giving up the offer to look at the lenses either through Control.Lens (each supposed battery) or fc-labels (easier). This allows you to carefully analyze your trees, which you can use in bi-directional mode, to view and create Endo s updates. They also have clever general principles, such as the ability to โ€œfocusโ€ on multiple locations on your tree at the same time (these are Fold and Traversal in Control.Lens ).

+1
source

Source: https://habr.com/ru/post/1493608/


All Articles