8

これは、特定のモナド アクションの動作を調査するために使用してきたイベント ネットワークのサンプルです。コードをテストするこのアドホックな方法ではなく、原則に基づいたアプローチが必要です。自分の関数をテストする方法は知っていますが、新しい設計の選択肢があるため、ビヘイビアとイベントをテストするためのベスト プラクティスを探しています。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にアップロードしてから投稿します。上記のリンクは、何をすべきかを整理するのに非常に役立ちました。

編集: 更新 - スタック テストを実行して型エラーが発生し、再度実行すると、テストが合格したという出力が得られます。結果として、私は昨日の私に近づいていません。コードとより明確な問題があります。そのために別の投稿を始めるかもしれません.ct

編集:更新 - 役立つ方法で壊れるテストがありますが、正確に何をすべきかわかりません。コンテキストのためにプロジェクト全体を投稿しました。以下に、テストコード、エラー、およびいくつかの説明のみを含めます。

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です。に持ち上げる必要がありますが、そうしないのはなぜですか。私の推論の何が問題になっていますか?IOMonadliftMomentMoment Behavior (BufferMap)IO Behavior (BufferMap)

4

1 に答える 1