2013-07-26 23 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

流暢的界面模式在Haskell中被稱爲Endo。這是一個Monoid,所以你可以使用mconcat獲得一些效率,但我很少看到Endo在實踐中使用,因爲它不是一個巨大的收益。

您將面臨這樣一個定義的一個挑戰是需要默認的所有東西,畢竟withName "My Test Case"將需要一個有效的TestCase本身。這可能意味着您的許多類型將爲Maybe,或者這可能意味着您需要仔細定義類型。這可能與你的標準語法樹的概念有關。

用於創建這種可擴展AST的全功能方法是使用Data types a la carte技術。簡而言之,您定義了一個通用的「sum」類型運算符,然後構建對遞歸類型的某些組件進行操作的函數。通過巧妙的默認設置,您可以省略許多樣板定義並考慮到可擴展性。

此類技術可能對您的類型有用。

最後,很難談論這樣的嵌套數據類型,而沒有拋出通過Control.Lens(包括所有可能的電池)或fc-labels(更簡單)來觀察鏡頭的建議。這些可以讓你對雙向使用的樹木進行深入檢查,以便查看和構建更新Endo。它們還具有明智的通用原則,例如可以同時「聚焦」樹中的多個位置(這些是和Traversal,位於Control.Lens中)。