HMock-0.5.1.0: A flexible mock framework for testing effectful code.
Safe HaskellNone
LanguageHaskell2010

Test.HMock.MockT

Description

This module defines monads for working with mocks. HMock tests run in the MockT monad transformer. A more limited monad, MockSetup, is used for setting up defaults for each class. Both are instances of the MockContext monad, which defines a shared API.

Synopsis

Documentation

data MockT m a Source #

Monad transformer for running mocks.

Instances

Instances details
MonadTrans MockT Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

lift :: Monad m => m a -> MockT m a #

ExpectContext MockT Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

expect :: forall (m :: Type -> Type) (cls :: (Type -> Type) -> Constraint) (name :: Symbol) r expectable. (HasCallStack, MonadIO m, MockableMethod cls name m r, Expectable cls name m r expectable) => expectable -> MockT m () Source #

expectN :: forall (m :: Type -> Type) (cls :: (Type -> Type) -> Constraint) (name :: Symbol) r expectable. (HasCallStack, MonadIO m, MockableMethod cls name m r, Expectable cls name m r expectable) => Multiplicity -> expectable -> MockT m () Source #

expectAny :: forall (m :: Type -> Type) (cls :: (Type -> Type) -> Constraint) (name :: Symbol) r expectable. (HasCallStack, MonadIO m, MockableMethod cls name m r, Expectable cls name m r expectable) => expectable -> MockT m () Source #

inSequence :: forall (m :: Type -> Type). MonadIO m => (forall (ctx' :: (Type -> Type) -> Type -> Type). ExpectContext ctx' => [ctx' m ()]) -> MockT m () Source #

inAnyOrder :: forall (m :: Type -> Type). MonadIO m => (forall (ctx' :: (Type -> Type) -> Type -> Type). ExpectContext ctx' => [ctx' m ()]) -> MockT m () Source #

anyOf :: forall (m :: Type -> Type). MonadIO m => (forall (ctx' :: (Type -> Type) -> Type -> Type). ExpectContext ctx' => [ctx' m ()]) -> MockT m () Source #

times :: forall (m :: Type -> Type). MonadIO m => Multiplicity -> (forall (ctx' :: (Type -> Type) -> Type -> Type). ExpectContext ctx' => ctx' m ()) -> MockT m () Source #

consecutiveTimes :: forall (m :: Type -> Type). MonadIO m => Multiplicity -> (forall (ctx' :: (Type -> Type) -> Type -> Type). ExpectContext ctx' => ctx' m ()) -> MockT m () Source #

MockContext MockT Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

fromMockSetup :: forall (m :: Type -> Type) a. MonadIO m => MockSetup m a -> MockT m a Source #

(MonadReader r m, MonadWriter w m, MonadState s m) => MonadRWS r w s (MockT m) Source # 
Instance details

Defined in Test.HMock.Internal.State

MonadBase b m => MonadBase b (MockT m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

liftBase :: b α -> MockT m α #

MonadWriter w m => MonadWriter w (MockT m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

writer :: (a, w) -> MockT m a #

tell :: w -> MockT m () #

listen :: MockT m a -> MockT m (a, w) #

pass :: MockT m (a, w -> w) -> MockT m a #

MonadState s m => MonadState s (MockT m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

get :: MockT m s #

put :: s -> MockT m () #

state :: (s -> (a, s)) -> MockT m a #

MonadReader r m => MonadReader r (MockT m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

ask :: MockT m r #

local :: (r -> r) -> MockT m a -> MockT m a #

reader :: (r -> a) -> MockT m a #

MonadError e m => MonadError e (MockT m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

throwError :: e -> MockT m a #

catchError :: MockT m a -> (e -> MockT m a) -> MockT m a #

Monad m => Monad (MockT m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

(>>=) :: MockT m a -> (a -> MockT m b) -> MockT m b #

(>>) :: MockT m a -> MockT m b -> MockT m b #

return :: a -> MockT m a #

Functor m => Functor (MockT m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

fmap :: (a -> b) -> MockT m a -> MockT m b #

(<$) :: a -> MockT m b -> MockT m a #

MonadFail m => MonadFail (MockT m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

fail :: String -> MockT m a #

Applicative m => Applicative (MockT m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

pure :: a -> MockT m a #

(<*>) :: MockT m (a -> b) -> MockT m a -> MockT m b #

liftA2 :: (a -> b -> c) -> MockT m a -> MockT m b -> MockT m c #

(*>) :: MockT m a -> MockT m b -> MockT m b #

(<*) :: MockT m a -> MockT m b -> MockT m a #

MonadIO m => MonadIO (MockT m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

liftIO :: IO a -> MockT m a #

MonadThrow m => MonadThrow (MockT m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

throwM :: Exception e => e -> MockT m a #

MonadCatch m => MonadCatch (MockT m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

catch :: Exception e => MockT m a -> (e -> MockT m a) -> MockT m a #

MonadMask m => MonadMask (MockT m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

mask :: ((forall a. MockT m a -> MockT m a) -> MockT m b) -> MockT m b #

uninterruptibleMask :: ((forall a. MockT m a -> MockT m a) -> MockT m b) -> MockT m b #

generalBracket :: MockT m a -> (a -> ExitCase b -> MockT m c) -> (a -> MockT m b) -> MockT m (b, c) #

MonadCont m => MonadCont (MockT m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

callCC :: ((a -> MockT m b) -> MockT m a) -> MockT m a #

MonadUnliftIO m => MonadUnliftIO (MockT m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

withRunInIO :: ((forall a. MockT m a -> IO a) -> IO b) -> MockT m b #

runMockT :: forall m a. MonadIO m => MockT m a -> m a Source #

Runs a test in the MockT monad, handling all of the mocks.

withMockT :: forall m b. MonadIO m => ((forall a. MockT m a -> m a) -> MockT m b) -> m b Source #

Runs a test in the MockT monad. The test can unlift other MockT pieces to the base monad while still acting on the same set of expectations. This can be useful for testing concurrency or similar mechanisms.

test = withMockT $ inMockT -> do
   expect $ ...

   liftIO $ forkIO $ inMockT firstThread
   liftIO $ forkIO $ inMockT secondThread

This is a low-level primitive. Consider using the unliftio package for higher level implementations of multithreading and other primitives.

nestMockT :: forall m a. MonadIO m => MockT m a -> MockT m a Source #

Starts a nested block within MockT. The nested block has its own set of expectations, which must be fulfilled before the end of the block.

Beware: use of nestMockT might signify that you are doing too much in a single test. Consider splitting large tests into a separate test for each case.

withNestedMockT :: forall m b. MonadIO m => ((forall a. MockT m a -> m a) -> MockT m b) -> MockT m b Source #

Starts a nested block within MockT. The nested block has its own set of expectations, which must be fulfilled before the end of the block. It can unlift other MockT pieces to the base monad while still acting on the same set of expectations. This can be useful for testing concurrency or similar mechanisms.

Beware: use of nestMockT might signify that you are doing too much in a single test. Consider splitting large tests into a separate test for each case.

data Severity Source #

The severity for a possible problem.

Constructors

Error

Fail the test.

Warning

Print a message, but continue the test.

Ignore

Don't do anything.

setAmbiguityCheck :: MonadIO m => Severity -> MockT m () Source #

Sets the severity for ambiguous actions. An ambiguous action is one that matches expectations in more than one way. If this is not set to Error, the most recently added expectation will take precedence.

This defaults to Ignore.

setUninterestingActionCheck :: MonadIO m => Severity -> MockT m () Source #

Sets the severity for uninteresting actions. An uninteresting action is one for which no expectations or other configuration have been added that mention the method at all. If this is not set to Error, then uninteresting methods are treated just like unexpected methods.

Before you weaken this check, consider that the labeling of methods as "uninteresting" is non-compositional. A change in one part of your test can result in a formerly uninteresting action being considered interesting in a different part of the test.

This defaults to Error.

setUnexpectedActionCheck :: MonadIO m => Severity -> MockT m () Source #

Sets the severity for unexpected actions. An unexpected action is one that doesn't match any expectations *and* isn't explicitly allowed by allowUnexpected. If this is not set to Error, the action returns its default response.

This defaults to Error.

setUnmetExpectationCheck :: MonadIO m => Severity -> MockT m () Source #

Sets the severity for unmet expectations. An unmet expectation happens when an expectation is added, but either the test (or nesting level) ends or verifyExpectations is used before a matching action takes place.

This defaults to Error.

describeExpectations :: MonadIO m => MockT m String Source #

Fetches a String that describes the current set of outstanding expectations. This is sometimes useful for debugging test code. The exact format is not specified.

verifyExpectations :: MonadIO m => MockT m () Source #

Verifies that all mock expectations are satisfied. If there is a nested block in effect, only the expectations of that nested block are verified You normally don't need to do this, because it happens automatically at the end of your test or nested block. However, it's occasionally useful to check expectations early.

Beware: use of verifyExpectations might signify that you are doing too much in a single test. Consider splitting large tests into a separate test for each case.

data MockSetup m a Source #

Monad for setting up a mockable class. Note that even though the type looks that way, this is *not* a monad transformer. It's a very restricted environment that can only be used to set up defaults for a class.

Instances

Instances details
ExpectContext MockSetup Source #

This instance allows you to add expectations from MockSetup actions. This is an unusual thing to do. Consider using allowUnexpected, instead.

Instance details

Defined in Test.HMock.Internal.State

Methods

expect :: forall (m :: Type -> Type) (cls :: (Type -> Type) -> Constraint) (name :: Symbol) r expectable. (HasCallStack, MonadIO m, MockableMethod cls name m r, Expectable cls name m r expectable) => expectable -> MockSetup m () Source #

expectN :: forall (m :: Type -> Type) (cls :: (Type -> Type) -> Constraint) (name :: Symbol) r expectable. (HasCallStack, MonadIO m, MockableMethod cls name m r, Expectable cls name m r expectable) => Multiplicity -> expectable -> MockSetup m () Source #

expectAny :: forall (m :: Type -> Type) (cls :: (Type -> Type) -> Constraint) (name :: Symbol) r expectable. (HasCallStack, MonadIO m, MockableMethod cls name m r, Expectable cls name m r expectable) => expectable -> MockSetup m () Source #

inSequence :: forall (m :: Type -> Type). MonadIO m => (forall (ctx' :: (Type -> Type) -> Type -> Type). ExpectContext ctx' => [ctx' m ()]) -> MockSetup m () Source #

inAnyOrder :: forall (m :: Type -> Type). MonadIO m => (forall (ctx' :: (Type -> Type) -> Type -> Type). ExpectContext ctx' => [ctx' m ()]) -> MockSetup m () Source #

anyOf :: forall (m :: Type -> Type). MonadIO m => (forall (ctx' :: (Type -> Type) -> Type -> Type). ExpectContext ctx' => [ctx' m ()]) -> MockSetup m () Source #

times :: forall (m :: Type -> Type). MonadIO m => Multiplicity -> (forall (ctx' :: (Type -> Type) -> Type -> Type). ExpectContext ctx' => ctx' m ()) -> MockSetup m () Source #

consecutiveTimes :: forall (m :: Type -> Type). MonadIO m => Multiplicity -> (forall (ctx' :: (Type -> Type) -> Type -> Type). ExpectContext ctx' => ctx' m ()) -> MockSetup m () Source #

MockContext MockSetup Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

fromMockSetup :: forall (m :: Type -> Type) a. MonadIO m => MockSetup m a -> MockSetup m a Source #

Monad (MockSetup m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

(>>=) :: MockSetup m a -> (a -> MockSetup m b) -> MockSetup m b #

(>>) :: MockSetup m a -> MockSetup m b -> MockSetup m b #

return :: a -> MockSetup m a #

Functor (MockSetup m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

fmap :: (a -> b) -> MockSetup m a -> MockSetup m b #

(<$) :: a -> MockSetup m b -> MockSetup m a #

Applicative (MockSetup m) Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

pure :: a -> MockSetup m a #

(<*>) :: MockSetup m (a -> b) -> MockSetup m a -> MockSetup m b #

liftA2 :: (a -> b -> c) -> MockSetup m a -> MockSetup m b -> MockSetup m c #

(*>) :: MockSetup m a -> MockSetup m b -> MockSetup m b #

(<*) :: MockSetup m a -> MockSetup m b -> MockSetup m a #

class MockContext ctx Source #

This type class defines a shared API between the MockT and MockSetup monads.

Minimal complete definition

fromMockSetup

Instances

Instances details
MockContext MockSetup Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

fromMockSetup :: forall (m :: Type -> Type) a. MonadIO m => MockSetup m a -> MockSetup m a Source #

MockContext MockT Source # 
Instance details

Defined in Test.HMock.Internal.State

Methods

fromMockSetup :: forall (m :: Type -> Type) a. MonadIO m => MockSetup m a -> MockT m a Source #

allowUnexpected :: forall cls name m r rule ctx. (MonadIO m, MockableMethod cls name m r, Expectable cls name m r rule, MockContext ctx) => rule -> ctx m () Source #

Adds a handler for unexpected actions. Matching calls will not fail, but will use a default response instead. The rule passed in must have zero or one responses: if there is a response, allowUnexpected (m |=> r) is equivalent to allowUnexpected m >> byDefault (m |=> r).

The difference between expectAny and allowUnexpected is subtle, but comes down to ambiguity:

  • allowUnexpected is not an expectation, so it cannot be ambiguous. It only has an effect if no true expectation matches, regardless of when the expectations were added.
  • expectAny adds an expectation, so if another expectation is in effect at the same time, a call to the method is ambiguous. If ambiguity checking is enabled, the method will throw an error; otherwise, the more recently added of the two expectations is used.

byDefault :: forall cls name m r ctx. (MonadIO m, MockableMethod cls name m r, MockContext ctx) => Rule cls name m r -> ctx m () Source #

Sets a default action for *expected* matching calls. The new default only applies to calls for which an expectation exists, but it lacks an explicit response. The rule passed in must have exactly one response.

whenever :: forall cls name m r ctx. (MonadIO m, MockableMethod cls name m r, MockContext ctx) => Rule cls name m r -> ctx m () Source #

Adds a side-effect, which happens whenever a matching call occurs, in addition to the usual response. The return value is entirely ignored.

Be warned: using side effects makes it easy to break abstraction boundaries. Be aware that there may be other uses of a method besides the one which you intend to intercept here. If possible, add the desired behavior to the response for the matching expectation instead.