liveBook · Manning

Mock interpreter

As explained in Functional Design and Architecture: Examples in Haskell

A mock interpreter is an interpreter implementation that simulates effects or external actions for isolated testing.

A mock interpreter replaces live effects with controlled results, letting isolated tests exercise business logic without invoking native or external functions. A dedicated interpreter keeps testing behavior separate from the live interpreter; configurable mocks can also preserve selected real effects. section 15.2.2 section 15.2.3

A practical mock interpreter typically supports:

  • Descending through hierarchical actions when a test needs to mock lower-level calls rather than only the outer operation. section 15.2.3

Driving a random activity scenario

A random activity selector first chooses an activity and may then choose a game. Supplying [3, 2] routes execution through the computer-game branch and selects “Dwarf Fortress,” making a nondeterministic path testable.

Listing 15.15 Updated white-box test that uses a real runtime
spec :: Spec
spec
  = around withAppRuntime
  $ describe "Labyrinth KV DB tests"
  $ it "Load player position should throw exception" 
  $ \appRt -> do
  
    mocksVar <- newIORef
      [ (0, RunRealInterpreter)                    #1
      , (1, Mock (MockedKVDBConn "LabKVDB"))       #2
      , (2, Mock (Right testKVDBLabyrinth))
      , (3, RunRealInterpreter)                    #3
      , (4, Mock (MockedKVDBConn "LabKVDB"))       #4
      , (5, Mock (Left (DBError "KVDB Failure")))
      , (6, RunRealInterpreter)                    #5
      ]
  
    let testRt = TestRuntime (Just appRt) mocksVar
    let action = loadGame testKVDBConfig 1
  
    eGameState <- try (Test.runAppL testRt action)
    case eGameState of
      Left (e :: SomeException) -> 
         show e `shouldBe` "Failed to load the player pos"
      Right _ -> fail "Test failed"

Inspect a white-box test that mixes mocked calls with RunRealInterpreter entries, showing how a test runtime can combine simulated and live evaluation. section 15.2.3

How Functional Design and Architecture: Examples in Haskell covers it

How deep it goes
Defines fixed, parameterized, stateful, hierarchical, and mixed-runtime strategies, stopping short of a general mocking framework.
Examples
Demonstrates random activity selection, sequential random values, database loading failures, and a test runtime mixing mocks with live interpreters.
What it assumes
Assumes free-monad interpreters and effectful application actions, while teaching test doubles through concrete random and database scenarios.
What you can do after
Build it from scratch as a configurable interpreter that drives deterministic branches and selectively evaluates real effects.
How it connects
Connects free monads, interpreters, white-box testing, black-box integration testing, and real-effect evaluation.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Functional Design and Architecture: Examples in Haskell. The section links point to the parts of the book it draws on.