这是我用来调查特定monadic动作行为的事件网络示例.我想要一种原则性的方法,而不是这种测试我的代码的特殊方式.我知道如何测试我的功能,但我正在寻找测试行为和事件的最佳实践,给出了新的设计选择reactive-banana 1.0.0
我遗漏了很多,希望我只包括说明问题的必要条件.请告诉我是否应该包含哪些内容,以使问题更加清晰.
makeNetworkDescription :: Parameters -> MomentIO () makeNetworkDescription params = mdo eInput <- fromAddHandler (input params) eTick <- fromAddHandler (tick params) let eValidated :: Event VAC eValidated = toVAC <$> eInput eClearBuffer = Clear <$ eBuffer eBuffer ::Event BufferMap eBuffer = bBuffer <@ eTick bBuffer <- accumB (BufferMap (M.empty :: M.Map AID VAC)) $ manageBuffer <$> unionWith (clearBuffer) eValidated eClearBuffer reactimate $ writeOut_Debug <$> eBuffer
缓冲区应该做的是累积的播放器命令(然后在其他地方处理),然后在处理特定批次的播放器命令后清空.在下一次打勾时,它会再次发生.
我希望确保缓冲区在它应该被清除时被清除,并且像它应该那样累积命令.现在,代码工作,我想编写测试,以确保它在我构建这个游戏时继续工作.
我可以在上面的例子中将缓冲区Behavior
与Event
网络分开,但那又如何呢?从测试中获得准确结果的最佳方法是什么?
编辑:更新 - 我相信此链接将提供足够的提示.我会对它进行一次尝试并明天报告更多细节.
编辑:更新 - 我写了一个单元测试.我会上传到github,当它是purty,然后发布.以上链接非常有助于理清该做什么.
编辑:更新 - 如果您运行堆栈测试并且存在类型错误,然后再次运行它,您将获得表明您的测试已通过的输出.结果是,我和昨天的关系并不紧密.我有代码和更清晰的问题.我可以为那个开始一个不同的帖子
编辑:更新 - 我的测试以一种有用的方式打破,但我不知道该怎么做.我已经发布了整个项目的上下文.下面我只包括测试代码,错误和一些讨论.
main :: IO () main = defaultMain [ testGroup "EventNetwork Input" [testBuffer "bBuffer" Populated] ] testBuffer :: String -> BufferState -> Test testBuffer name Populated = testCase name $ assert $ bufferPopulated (UAC (PlayerCommand (Move (ToPlanetName Mongo)) (AID (Data.Text.pack "100")))) testBuffer name Empty = testCase name $ assert $ bufferEmptied (UAC (PlayerCommand (Move (ToPlanetName Mongo)) (AID (Data.Text.pack "100")))) bufferPopulated :: UAC -> MomentIO Bool bufferPopulated ev = do let eInput = ev <$ never eValidated = toVAC <$> eInput bBufferMap <- (buffer eValidated eClear) :: MomentIO (Behavior BufferMap) let r2 = [(Just $ BufferMap $ M.insert (AID (Data.Text.pack "100")) (toVAC ev) (M.empty :: M.Map AID VAC))] r1 <- liftIO $ ((interpret (eBuffer bBufferMap) []) :: IO [Maybe BufferMap]) return $ r1 == r2 bufferEmptied :: UAC -> MomentIO Bool bufferEmptied ev = undefined eBuffer :: Behavior BufferMap -> Event a -> Event BufferMap eBuffer bBufferMap nvr = bBufferMap <@ (() <$ nvr) eClear = Clear <$ (() <$ never) tests/Spec.hs:26:19: No instance for (Test.HUnit.Base.Assertable (MomentIO Bool)) arising from a use of ‘assert’ In the expression: assert In the second argument of ‘($)’, namely ‘assert $ bufferPopulated (UAC (PlayerCommand (Move (ToPlanetName Mongo)) (AID (pack "100"))))’ In the expression: testCase name $ assert $ bufferPopulated (UAC (PlayerCommand (Move (ToPlanetName Mongo)) (AID (pack "100"))))
问题归结为accumB
创建Behavior
一个MomemtIO
.如果我bufferPopulated
回来了IO Bool
,我怎么能和解呢?
编辑:显而易见的是编写它想要的实例.我想这可能是一个红鲱鱼.你怎么看.这只是编写MomentIO Bool
实例这么简单吗?
编辑:更新我认为我走在正确的轨道上.我已经注释掉了所有测试工具代码并更改了签名bufferPopulated
bufferPopulated :: UAC -> IO Bool bufferPopulated ev = do let eInput = ev <$ never eValidated = toVAC <$> eInput bBufferMap <- liftMoment ((buffer eValidated eClear) :: Moment (Behavior BufferMap)) let r2 = [(Just $ BufferMap $ M.insert (AID (Data.Text.pack "100")) (toVAC ev) (M.empty :: M.Map AID VAC))] r1 <- (interpret (eBuffer bBufferMap) []) :: IO [Maybe BufferMap]) return $ r1 == r2
我相信这应该有效,但这是错误
tests/Spec.hs:35:17: No instance for (MonadMoment IO) arising from a use of ‘liftMoment’ In a stmt of a 'do' block: bBufferMap <- liftMoment ((buffer eValidated eClear) :: Moment (Behavior BufferMap))
让我们来看看MonadMoment
从Reactive.Banana.Combinators
class Monad m => MonadMoment m where An instance of the MonadMoment class denotes a computation that happens at one particular moment in time. Unlike the Moment monad, it need not be pure anymore. Methods liftMoment :: Moment a -> m a Instances MonadMoment MomentIO MonadMoment Moment
m
可以是任何Monad
,IO
是一个Monad
.所以liftMoment
应该举起Moment Behavior (BufferMap)
来IO Behavior (BufferMap)
,为什么不呢.我的推理有什么问题?