명령 줄 인수를 사용하여 화면에 출력하는 작은 함수 (또는 IO 동작)를 테스트하려고합니다. 내 원래 (검증 할) 기능은 다음과 같습니다IO 작업 조롱 : getArgs 및 putStrLn
-- In Library.hs
module Library where
import System.Environment (getArgs)
run :: IO()
run = do
args <- getArgs
putStrLn $ head args
this answer about mocking보고 후, 나는 타입 클래스 제약 형식을 사용하여 getArgs
및 putStrLn
을 조롱 수있는 방법을 마련했다. 그래서 위의 함수가된다 :
-- In Library.hs
module Library where
class Monad m => SystemMonad m where
getArgs :: m [String]
putStrLn :: String -> m()
instance SystemMonad IO where
getArgs = System.Environment.getArgs
putStrLn = Prelude.putStrLn
run :: SystemMonad m => m()
run = do
args <- Library.getArgs
Library.putStrLn $ head args
이
Library.
,
Prelude.
및 System.Environment.
이 Ambigious Occurence
의 컴파일러 불만을 방지한다. 내 테스트 파일은 다음과 같습니다.
-- In LibrarySpec.hs
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
import Library
import Test.Hspec
import Control.Monad.State
data MockArgsAndResult = MockArgsAndResult [String] String
deriving(Eq, Show)
instance SystemMonad (State MockArgsAndResult) where
getArgs = do
MockArgsAndResult args _ <- get
return args
putStrLn string = do
MockArgsAndResult args _ <- get
put $ MockArgsAndResult args string
return()
main :: IO()
main = hspec $ do
describe "run" $ do
it "passes the first command line argument to putStrLn" $ do
(execState run (MockArgsAndResult ["first", "second"] "")) `shouldBe` (MockArgsAndResult ["first", "second"] "first")
효과적으로 2 개의 필드를 포함하는 State
모나드를 사용하고 있습니다.
- 모의
getArgs
이 모의putStrLn
가 전달 된 것을두고 있음을 - 에서 문자열을 읽는 명령 행 인수에 대한 목록입니다.
위의 코드는 작동하며 내가 테스트하고 싶은 것을 테스트하는 것으로 보입니다. 그러나,이 더 나은/청소기/더 많은 관용적 인 방법이 있는지 궁금하네요. 한 가지는, 같은 상태를 사용하여 테스트에 물건을 넣고 (내 가짜 명령 행 인수) putStrLn
에 전달 된 내용입니다.
더 좋은 방법이 있습니까? 내가하고있는 일을하고 있니? 나는 Javascript 환경에서 조롱하는 것에 더 익숙하다. 하스켈에 대한 나의 지식은 꽤 기초적이다. (나는 실제적인 이해가 아니라 시행 착오의 공정한 비트에 의해 위의 해결책에 도달했다.)
나는 당신의 코드가 좋은/깨끗한/관용적이라고 생각합니다. 진짜 질문은 이것이 당신의 문제를 해결하는 것인가? "모델"은 모델링중인 실제 "파일 시스템"을 정확하게 나타 내기에 충분한가요? 그렇다면 아마도 이것을 과장 할 필요가 없을 것입니다. 그러나'PutStrLn'은'Prelude.putStrLn'을 실제로 시뮬레이트하고 싶다면 아마도 이전 문자열을 무시하는 대신에 문자열 인수를 상태의 이전 문자열에 추가해야합니다. – user2407038
@ user2407038 오래된 문자열에 추가하는 것은 좋은 생각입니다. –