IT Share you

Haskell 단위 테스트

shareyou 2020. 11. 8. 11:32
반응형

Haskell 단위 테스트


저는 haskell을 처음 사용하고 단위 테스트를 진행하고 있지만 생태계가 매우 혼란 스럽습니다. HTF와 HUnit의 관계에 대해 혼란 스럽습니다.

일부 예에서는 테스트 케이스를 설정하고 테스트 목록으로 내 보낸 다음 ghci에서 실행하는 것을 볼 수 있습니다 runTestsTT( 예 : HUnit 예제 ).

다른 예제에서는이 git 예제 와 같이 테스트를 찾기 위해 일부 전 처리기 마법을 사용하는 cabal 파일에 연결된 테스트 실행기를 만듭니다 . 또한 HTF 테스트에 접두사를 붙여야 test_하거나 실행되지 않는 것 같습니다. 나는 그것에 대한 문서를 찾기가 어려웠고 모든 사람들이 가진 패턴을 발견했습니다.

어쨌든, 누군가 나를 위해 이것을 분류하도록 도울 수 있습니까? Haskell에서 작업을 수행하는 표준 방식은 무엇입니까? 모범 사례는 무엇입니까? 설정 및 유지 관리가 가장 쉬운 것은 무엇입니까?


일반적으로 중요한 Haskell 프로젝트는 Cabal 과 함께 실행됩니다 . 이것은 구축, 배포, 문서화 (해독의 도움으로) 및 테스트를 처리합니다.

표준 접근 방식은 테스트를 test디렉터리에 넣은 다음 .cabal파일에 테스트 스위트를 설정하는 것 입니다. 이것은 사용자 매뉴얼에 자세히 설명되어 있습니다 . 내 프로젝트 중 하나의 테스트 스위트는 다음과 같습니다.

Test-Suite test-melody
  type:               exitcode-stdio-1.0
  main-is:            Main.hs
  hs-source-dirs:     test
  build-depends:      base >=4.6 && <4.7,
                      test-framework,
                      test-framework-hunit,
                      HUnit,
                      containers == 0.5.*

그런 다음 파일에서 test/Main.hs

import Test.HUnit
import Test.Framework
import Test.Framework.Providers.HUnit
import Data.Monoid
import Control.Monad
import Utils

pushTest :: Assertion
pushTest = [NumLit 1] ^? push (NumLit 1)

pushPopTest :: Assertion
pushPopTest = [] ^? (push (NumLit 0) >> void pop)

main :: IO ()
main = defaultMainWithOpts
       [testCase "push" pushTest
       ,testCase "push-pop" pushPopTest]
       mempty

HUnitUtils 보다 멋진 인터페이스를 정의하는 입니다.

더 가벼운 테스트를 위해서는 QuickCheck 를 사용하는 것이 좋습니다 . 짧은 속성을 작성하고 일련의 임의 입력에 대해 테스트 할 수 있습니다. 예를 들면 :

 -- Tests.hs
 import Test.QuickCheck

 prop_reverseReverse :: [Int] -> Bool
 prop_reverseReverse xs = reverse (reverse xs) == xs

그리고

 $ ghci Tests.hs
 > import Test.QuickCheck
 > quickCheck prop_reverseReverse
 .... Passed Tests (100/100)

저는 또한 초보 haskeller이고이 소개가 정말 도움이된다는 것을 발견했습니다 : " HUnit 시작하기 ". 요약하면 .cabal프로젝트 파일 없이 HUnit 사용에 대한 간단한 테스트 예를 여기에 넣겠습니다 .

모듈이 있다고 가정합시다 SafePrelude.hs.

module SafePrelude where

safeHead :: [a] -> Maybe a
safeHead []    = Nothing
safeHead (x:_) = Just x

TestSafePrelude.hs다음과 같이 테스트를 넣을 수 있습니다 .

module TestSafePrelude where

import Test.HUnit
import SafePrelude

testSafeHeadForEmptyList :: Test
testSafeHeadForEmptyList = 
    TestCase $ assertEqual "Should return Nothing for empty list"
                           Nothing (safeHead ([]::[Int]))

testSafeHeadForNonEmptyList :: Test
testSafeHeadForNonEmptyList =
    TestCase $ assertEqual "Should return (Just head) for non empty list" (Just 1)
               (safeHead ([1]::[Int]))

main :: IO Counts
main = runTestTT $ TestList [testSafeHeadForEmptyList, testSafeHeadForNonEmptyList]

이제 다음을 사용하여 테스트를 쉽게 실행할 수 있습니다 ghc.

runghc TestSafePrelude.hs

또는 hugs-이 경우 (내가 포옹에 익숙한 한) TestSafePrelude.hs이름을 변경해야합니다 Main.hs(모듈 헤더도 변경하는 것을 잊지 마십시오).

runhugs Main.hs

또는 다른 haskell컴파일러 ;-)

Of course there is more then that in HUnit, so I really recommend to read suggested tutorial and library User's Guide.


You've had answers to most of your questions, but you also asked about HTF, and how that works.

HTF is a framework that is designed for both unit testing -- it is backwards compatible with HUnit (it integrates and wraps it to provide extra functions) -- and property-based testing -- it integrates with quickcheck. It uses a preprocessor to locate tests so that you don't have to manually build a list. The preprocessor is added to your test source files using a pragma:

{-# OPTIONS_GHC -F -pgmF htfpp #-}

(alternatively, I guess you could add the same options to your ghc-options property in your cabal file, but I've never tried this so don't know if it is useful or not).

The preprocessor scans your module for top-level functions named test_xxxx or prop_xxxx and adds them to a list of tests for the module. You can either use this list directly by putting a main function in the module and running them (main = htfMain htf_thisModuleTests) or export them from the module, and have a main test program for multiple modules, which imports the modules with tests and runs all of them:

import {-@ HTF_TESTS @-} ModuleA
import {-@ HTF_TESTS @-} ModuleB
main :: IO ()
main = htfMain htf_importedTests

This program can be integrated with cabal using the technique described by @jozefg, or loaded into ghci and run interactively (although not on Windows - see https://github.com/skogsbaer/HTF/issues/60 for details).

Tasty is another alternative that provides a way of integrating different kinds of tests. It doesn't have a preprocessor like HTF, but has a module that performs similar functions using Template Haskell. Like HTF, it also relies on naming convention to identify your tests (in this case, case_xxxx rather than test_xxxx). In addition to HUnit and QuickCheck tests, it also has modules for handling a number of other test types.

참고URL : https://stackoverflow.com/questions/20331209/haskell-unit-testing

반응형