unit-testing - Reactive Banana 1.0.0 - MomentIO() Monad 中的单元测试

标签 unit-testing haskell reactive-banana

这是一个事件网络示例,我一直在使用它来调查特定单子(monad) Action 的行为。我想要一种有原则的方法,而不是这种测试我的代码的临时方法。我知道如何测试我的功能,但我正在寻找测试行为和事件的最佳实践,因为 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

缓冲区应该做的是累积的玩家命令(然后将在其他地方处理),然后在处理特定批处理的玩家命令后清空。在下一个滴答声中,它会再次发生。

我希望确保缓冲区在它应该被清除的时候被清除,并像它应该的那样积累命令。现在,代码可以工作,我想编写测试以确保它在我构建这个游戏时继续工作。

我可以制作缓冲区 BehaviorEvent 分开上例中的网络,但那又如何呢?从测试中获得准确结果的最佳方法是什么?

编辑:更新 - 我相信 this link将提供足够的提示。我会试一试,明天报告更多细节。

编辑:更新 - 我写了一个单元测试。我会在它的purty时上传到github,然后发布。上面的链接对于整理出要做什么非常有帮助。

编辑:更新 - 结果是,如果您运行堆栈测试并且存在类型错误,然后再次运行它,您会得到表明您的测试已通过的输出。结果是,我不再像昨天那样接近了。我有代码和一个更清晰的问题。我可能会为 that.ct 开始一个不同的帖子

编辑:更新 - 我有一个测试以一种有用的方式中断,但我不知道该怎么做。我已经发布了整个 project为上下文。下面我只包括测试代码、错误和一些讨论。
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创建 BehaviorMomemtIO .如果我有 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 , IOMonad .所以liftMoment应该解除Moment Behavior (BufferMap)IO Behavior (BufferMap) ,为什么不呢。我的推理有什么问题?

最佳答案

答案的来源来自这个先前的答案。

Testing in reactive-banana
interpretFramwork需要一个新的签名。

interpretFrameWorks'' :: (Event a -> MomentIO (Behavior b)) -> [a] ->  IO (b,[[b]])
interpretFrameWorks'' f xs = do
  output                      <- newIORef []
  init                        <- newIORef undefined
  (addHandler, runHandlers)   <- newAddHandler
  network                     <- compile $ do
    e <- fromAddHandler addHandler
    f' <- f e
    o <- changes $ f'
    i <- valueB $ f'
    liftIO $ writeIORef init i
    reactimate' $ (fmap . fmap) (\b -> modifyIORef output (++[b])) o

  actuate network
  bs <- forM xs $ \x -> do
      runHandlers x
      bs <- readIORef output
      writeIORef output []
      return bs
  i <- readIORef init
  return (i, bs)

关于unit-testing - Reactive Banana 1.0.0 - MomentIO() Monad 中的单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33613120/

相关文章:

visual-studio - 是否存在为 .NET 类预编写单元测试的工具?

python - 序列化器测试 serializer.is_valid() = False

java - 使用本地模拟器测试 PubsubIO 读取

performance - Data.Vector.Unboxed.Mutable.MVector 的索引真的这么慢吗?

haskell - FRP中的“Behavior now”

c# - 如何保留内存数据结构以便以后在单元测试中使用它

haskell - 没有数据构造函数的数据声明。可以实例化吗?为什么会编译?

Haskell - 无法将类型 ‘PersistEntityBackend record0’ 与 ‘SqlBackend’ 匹配

haskell - FRP框架和IO

haskell - 功能性 Banana Traveler - 独立于计时器和玩家的事件