2012-11-25 21 views
11

Jestem nowy w Haskell i próbuję utworzyć strukturę testowanego programu. Postanowiłem użyć HUnit i Cabal.Tworzenie pełnego stosu Haskell z testami

Z tego co widziałem to dobrze strucutred projekt wygląda następujące:

src/ 
    AppName/ 
    Appname.hs 
testsuite/ 
    tests/ 
    AppName/ 
    TestRunner.hs 
AppName.cabal 
Setup.hs 

części, które są tajemnicą dla mnie są TestRunner.hs i AppName.cabal.

Jak wyglądałby testrunner, który uruchamia wszystkie testy w katalogu testsuite/tests i podkatalogach? I jak można go zintegrować z Cabal?

Ponadto, w jaki sposób umieścić zależności hackage w AppName.cabal i budować je z wiersza poleceń?

Mam trudności ze znalezieniem pełnego przykładu budowania aplikacji od zera z testami i zależnościami.

Dzięki

+0

Czy odjazdu http://www.haskell.org/haskellwiki/How_to_write_a_Haskell_program? To może odpowiedzieć na niektóre z twoich pytań. –

Odpowiedz

18

Oto fragment pliku .cabal użyłem jednego z moich ostatnich libraries.

... 
Library 
    Build-depends:  base >= 4 && < 5, bytestring, directory, filepath, hslogger, 
         SHA, zlib 
    Ghc-options:   -Wall 
    Exposed-modules:  Ltc.Store 

Test-suite reference 
    Hs-Source-Dirs:  Test, . 
    Main-Is:    ReferenceProps.hs 
    Type:     exitcode-stdio-1.0 

    Build-Depends:  base >= 4 && < 5, bytestring, directory, filepath, hslogger, 
         SHA, zlib 
    Ghc-Options:   -Wall 

    Build-Depends:  test-framework, test-framework-hunit, test-framework-quickcheck2, 
         HUnit, QuickCheck 

Jak widać plik cabal definiuje bibliotekę i zestaw testowy. Biblioteka definiuje eksportowane moduły, pakiety, od których zależy, i ustawia niestandardowe opcje GHC.

Możemy łatwo budować i pakować bibliotekę do dystrybucji z:

% cabal configure 
% cabal build 
% cabal sdist 

testujące wygląda trochę jak biblioteki: po pierwsze, ma te same zależności jak biblioteka (patrz pierwszy Build-Depends linię), a następnie dodaje pewne dodatkowe zależności testowe (patrz druga linia Build-Depends). Testsuite jest kombinacją testów HUnit i QuickCheck, a jako runner używa Test-Framework. Właściwy test to . Jest to test typu exitcode-stdio. Oznacza to, że cabal powie, że testy zakończą się, jeśli ReferenceProps zakończy działanie z kodem 0. W przeciwnym razie powie, że testy się nie powiodły.

testsuite wygląda this (ale tu mamy zamiar użyć kilka prostych testów list odwrócenia):

import Data.Monoid 
import Test.Framework 
import Test.Framework.Providers.HUnit 
import Test.Framework.Providers.QuickCheck2 
import Test.HUnit 
import Test.QuickCheck 

main :: IO() 
main = defaultMainWithOpts 
     [ testCase "rev" testRev 
     , testProperty "listRevRevId" propListRevRevId 
     ] mempty 

testRev :: Assertion 
testRev = reverse [1, 2, 3] @?= [3, 2, 1] 

propListRevRevId :: [Int] -> Property 
propListRevRevId xs = not (null xs) ==> reverse (reverse xs) == xs 

main tylko uprząż. Możesz także ustawić różne opcje dla test-framework, zastępując mempty. Funkcja testRev jest testem HUnit, a propListRevRevId jest testem QuickCheck; patrz: relevantdocs w jaki sposób je zapisać.

Wreszcie możemy uruchomić testy:

% cabal configure --enable-tests 
% cabal test 
+0

Wielkie dzięki to odpowiada na większość moich pytań i podoba mi się sposób, w jaki łączyłeś się z githubem. Jeszcze jedno, jak byś uruchomił testy w podkatalogach Test /? Nie chcę umieszczać wszystkich moich testów w jednym pliku i byłoby wspaniale, gdyby podczas tworzenia pliku testowego testy były uruchamiane automatycznie w testamencie. – GTDev

+0

Są dwa sposoby, o których mogę pomyśleć: 1) dodać więcej sekcji "Test-Suite" do pliku cabal (to szybko się irytuje, ale prawdopodobnie jest to najprostsze rozwiązanie, jeśli masz tylko kilka zestawów testowych), lub 2) podziel testy na wiele plików, wyeksportuj listy testów w każdym pliku, a następnie użyj jednego programu do "konkatowania" list testów i ich uruchomienia. – scvalex

Powiązane problemy