HMock-0.5.1.2: README.md
# HMock - A Flexible Mock Framework for Haskell
[](https://github.com/cdsmith/HMock/actions/workflows/ci.yml)
[](https://hackage.haskell.org/package/HMock)
[HMock](https://hackage.haskell.org/package/HMock) provides a flexible and
composable mock framework for Haskell, with functionality that generally
matches or exceeds that of Mockito for Java, GoogleMock for C++, and other
mainstream languages.
WARNING: Hmock's API is likely to change soon. Please ensure you use an upper
bound on the version number. The current API works fine for mocking with
MTL-style classes. I want HMock to also work with effect systems, servant,
haxl, and more. To accomplish this, I'll need to make breaking changes to the
API.
## Quick Start
1. Define classes for the functionality you need to mock. To mock anything
with HMock, it needs to be implemented using a `Monad` subclass.
``` haskell
import Prelude hiding (readFile, writeFile)
import qualified Prelude
class Monad m => MonadFilesystem m where
readFile :: FilePath -> m String
writeFile :: FilePath -> String -> m ()
instance MonadFilesystem IO where
readFile = Prelude.readFile
writeFile = Prelude.writeFile
```
2. Implement the code to test, using this class.
``` haskell
copyFile :: MonadFilesystem m => FilePath -> FilePath -> m ()
copyFile a b = readFile a >>= writeFile b
```
3. Make the class `Mockable` using the provided Template Haskell splices.
``` haskell
makeMockable [t|MonadFilesystem|]
```
4. Set up expectations and run your code.
```haskell
test_copyFile :: IO ()
test_copyFile = runMockT $ do
expect $ ReadFile "foo.txt" |-> "contents"
expect $ WriteFile "bar.txt" "contents"
copyFile "foo.txt" "bar.txt"
```
* `runMockT` runs code in the `MockT` monad transformer.
* `expect` expects a method to be called exactly once.
* `ReadFile` and `WriteFile` match the function calls. They are defined
by `makeMockable`.
* `|->` separates the method call from its result. If it's left out, the
method will return a default value (see `Data.Default`), so there's no
need to specify `()` as a return value.
## Why mocks?
Mocks are not always the right tool for the job, but they play an important role
in testing practice.
* If possible, we prefer to test with actual code. Haskell encourages writing
much of the application logic with pure functions, which can be trivially
tested. However, this isn't all of the code, and bugs are quite likely to
appear in glue code that connects the core application logic to its outside
effects.
* If testing the actual code is not possible, we prefer to test with high
quality fake implementations. These work well for relatively simple effects.
However, they are difficult to maintain when the behavior of an external
system is complex, poorly specified, and/or frequently changing. Incomplete
or oversimplified fakes can make some of the most bug-prone code, such as
error handling and unusual cases, very difficult to test.
* Use of a mock framework allows a programmer to test code that uses complex
effectful interfaces, including all of the dark corners where nasty bugs tend
to hide. They also help to isolate test failures: when a component is broken,
one test fails and is easy to find, rather than everything downstream failing
at once.
## Why HMock?
HMock was designed to help Haskell programmers adopt good habits when testing
with mocks. When testing with mocks, there are some dangers to look out for:
* **Over-assertion** happens when your test requires things you don't care
about. If you read two files, you usually don't care in which order they are
read, so your tests should not require an order. Even when your code needs to
behave a certain way, you usually don't need to check that in every single
test. Each test should ideally test one property. However, a simplistic
approach to mocks may force you to over-assert just to run your code at all.
* **Over-stubbing** happens when you remove too much functionality from your
code, and end up assuming part of the logic you wanted to test. This makes
your test less useful. Again, a simplistic approach to mocks can lead you to
stub too much by not providing the right options to get realistic behavior
from your methods.
* **Fragile tests** happen when your expectations match too often or at
unexpected times, leading to incorrect behavior that's merely an artifact of
problems with mocks. Mainstream mock frameworks are not particularly
compositional, leading to frequent struggles with unexpected rules firing at
off times and breaking other tests.
HMock is designed to help you avoid these mistakes, by offering:
### Flexible ordering constraints
With HMock, you choose which constraints to enforce on the order of methods.
If certain methods need to happen in a fixed sequence, you can use `inSequence`
to check that. But if you don't care about the order, you need not check it.
If you don't care about certain methods at all, `expectAny` will let you set a
response without limiting when they are called. Using `expectN`, you can make
a method optional, or limit the number of times it can occur.
These tools let you express more of the exact properties you intend to test, so
that you don't fall into the over-assertion trap. This also unlocks the
opportunity to test concurrent or otherwise non-deterministic code.
### Flexible matchers
In HMock, you specify exactly what you care about in method parameters, by
using `Predicate`s. A `Predicate a` is essentially `a -> Bool`, except that it
can be printed for better error messages. If you want to match all parameters
exactly, there's a shortcut for doing so. But you can also ignore arguments you
don't care about, or only make partial assertions about their values. For
example, you can use `hasSubstr` to match a key word in a logging message,
without needing to copy and paste the entire string into your test.
Because you need not compare every argument, HMock can even be used to mock
methods whose parameters have no `Eq` instances at all. You can write a mock
for a method that takes a function as an argument, for example. You can even
mock polymorphic methods.
### Flexible responses
In HMock, you have a lot of options for what to do when a method is called.
For example:
1. You can look at the arguments. Need to return the third argument? No
problem; just look at the `Action` that's passed in.
2. You can invoke other methods. Need to forward one method to another? Want
to set up a lightweight fake without defining a new type and instance? It's
easy to do so.
3. You can add additional expectations. Need to be sure that every opened file
handle is closed? The response runs in `MockT`, so just add that expectation
when the handle is opened.
4. You can perform actions in a base monad. Need to modify some state for a
complex test? Need to keep a log of info so that you can assert a property
at the end of the test? Just run your test in `MockT (State Foo)` or
`MockT (Writer [Info])`, and call `get`, `put`, and `tell` from your
responses.
These flexible responses help you to avoid over-stubbing. You can even use
HMock to delegate to a lightweight fake. Not only does this avoid defining
a new type for each fake instance, but you can also easily inject errors and
other unusual behavior as exceptions to the fake implementation.
### Composable mocking primitives
HMock's expectations expand on the ideas from Svenningsson, et al. in [An
Expressive Semantics of Mocking](
https://link.springer.com/content/pdf/10.1007%2F978-3-642-54804-8_27.pdf).
The key idea is to offer compositional primitives. Anything you can do to a
single call, you can also do to an entire sequence of calls. You can express
repeated sequences of calls, choice between two options, etc. Because the core
mocking language is more expressive, you're less likely to need to stub out to
secondary mechanisms, such as recording calls and asserting about them later,
the way you may be used to in other languages, and this also makes your tests
more composable.
### Reusable mocks
With HMock, your mocks are independent of the specific monad stack or
combination of interfaces that your code uses. You can write tests using any
combination of `Mockable` classes, and each part of your test code depends only
on the classes that you use directly. This frees you to share convenience
libraries for testing, and reuse these components in different combinations
as needed.
You can also set up default behaviors for your mocks by implementing the
`Mockable` class manually, bundling sensible defaults with your derived mock
implementations for all users.
### Configurable Severity
HMock allows you to control the severity of several situations that can arise
during testing. You can modify each of these situations to be `Ignore`d,
trigger a `Warning` but continue the test, or throw an `Error`, by passing the
severity to a `MockT` action as explained below.
These conditions whose severity you can adjust are:
1. **Ambiguous expectations**
Ambiguious expectations happen when one action matches more than one
expectation. By default, this is `Ignore`d, and the most recently added
expectation is chosen.
Svenningsson, et al. argue that ambiguity resolution rules are non-composable
and that enforcing ambiguity is therefore necessary for composability. If
you agree, you may want to set a higher severity for ambiguous expectations.
To do so, use `setAmbiguityCheck`.
Note that unlike Svenningsson, et al., HMock verifies ambiguity dynamically
at runtime, so failures only occur when an actual action matches more than
one expectation., and not when it's merely possible for this to occur.
2. **Uninteresting actions**
An uninteresting action occurs when a method is called, but no expectations
have been added for that method at all. By default, this is an `Error`.
However, some other mock frameworks (for example, gMock) allow you to ignore
uninteresting actions. To do so in HMock, use `setUninterestingActionCheck`
to change this severity.
Ignoring uninteresting methods is non-composable. Adding an expectation for
a method in one part of your test will cause the method to be considered
"interesting", which can cause an unrelated part of the test to fail.
Note that `setUninterestingActionCheck Error` (the default) actually treats
uninteresting methods as unexpected. If you set a weaker severity for
unexpected actions, uninteresting actions will also follow that severity.
3. **Unexpected actions**
An unexpected action occurs when an action is called that has no
corresponding expectation. By default, this is an `Error`. Note that unless
uninteresting actions are also set to `Error`, an action is only unexpected
if there is at least one expectation added for the method. To change the
severity of unexpected actions, use `setUnexpectedActionCheck`.
This is generally intended as a temporary technique for collecting
information about which expectations are needed for a test. You should be
careful about leaving it this way. Prefer `allowUnexpected` if you just want
to ignore some specific unexpected actions.
4. **Unmatched expectations**
An unmatched expectation is an expectation that is not matched by any action
that occurs during the test. By default, this is an `Error`. You can change
this severity by calling `setUnmetExpectationCheck`.
This is generally intended as a temporary technique for collecting
information about which expectations are needed for a test. You should be
careful about leaving it this way.
## FAQ
Here are a few tips for making the most of HMock.
### What is the difference between `|->` and `|=>`?
In the most general form, an HMock rule contains a response of the form
`Action ... -> MockT m r`. The action contains the parameters, and the `MockT`
monad can be used to add expectations or do things in the base monad. You can
build such a rule using `|=>`.
However, it's very common that you don't need this flexibility, and just want
to specify the return value. In that case, you can use `|->` instead to keep
things a bit more readable. `m |-> r` is short for `m |=> const (return r)`.
As a mnemonic device for remembering the distinction, you can think of:
* `|->` as ASCII art for `↦`, which associates a function with a result in
mathematical notation.
* `|=>` as a relative of Haskell's `>>=`, and binds an operation to a Kleisli
arrow.
### What is the difference between `foo`, `Foo`, and `Foo_`?
These three names have subtly different meanings:
* `foo` is the method of your own class. This is the function used in the code
that you are testing.
* `Foo` is an `Action` constructor representing a call to the method. You will
typically use this in three places: in an expectation when you know the exact
expected arguments, as the argument to `mockMethod` and friends, and as a
pattern to get the parameters in a response.
* `Foo_` is the `Matcher` constructor, and expects `Predicate`s that can match
the arguments in more general ways without specifying their exact values.
This is more powerful, but a bit wordier, than writing an expectation using
the action `Foo`. You must also use `Foo_` for expectations when the method
parameters lack `Eq` or `Show` instances.
### Can I mock only some methods of a class?
Yes!
The `makeMockable` splice is the simple way to set up mocks for a class, and
delegates everything in the class to HMock to match with expectations. However,
sometimes you either can't or don't want to delegate all of your methods to
HMock. In that case, use the `makeMockableWithOptions` splice, instead, and set
`mockDeriveForMockT` to `False`. This implements most of the deeper boilerplate
for HMock, but doesn't define the instance for `MockT`. You will define that
yourself using `mockMethod` and friends.
For example:
``` haskell
class MonadFoo m where
mockThis :: String -> m ()
butNotThis :: Int -> m String
makeMockableWithOptions [t|MonadFoo|] def { mockDeriveForMockT = False }
instance (Monad m, Typeable m) => MonadFoo (MockT m) where
mockThis x = mockMethod (MockThis x)
butNotThis _ = return "fake, not mock"
```
If your class has methods that HMock cannot handle, then you **must** do this.
These include things like associated types, methods that don't run in the monad,
or methods with non-`Typeable` polymorphic return values.
### How do I mock methods with polymorphic arguments?
HMock can be used to write mocks with polymorphic arguments, but there are a few
quirks to keep in mind.
First, let's distinguish between two types of polymorphic arguments. Consider
this class:
``` haskell
class MonadPolyArgs a m where
foo :: a -> m ()
bar :: b -> m ()
```
In `foo`, the argument type `a` is bound by the *instance*. Instance-bound
arguments act just like concrete types, for the most part, but check out the
later question about multi-parameter type classes for some details.
In `bar`, the argument type `b` is bound by the *method*. Because of this, the
`Matcher` for `bar` will be assigned the rank-n type
`(forall b. Predicate b) -> Matcher ...`. In fact, pretty much the only
`Predicate` you could use in such a type is `anything` (which always matches, no
matter the argument value). Since `eq` is not legal here, the corresponding
`Action` type will not get an `Expectable` instance, so you may not use it
to match an exact call to `bar`.
In order to write a more specific predicate, you'd need to add constraints to
`bar` in the original class. Understandably, you may be reluctant to modify
your functional code for the sake of testing, but in this case there is no
alternative. Any constraints that you add to the method can be used in
`Predicate`s in the `Matcher`. For example, if `bar` can be modified to add a
`Typeable` constraint, then you can use a predicate like `typed @Int (lt 5)`,
which will only match calls where `b` is `Int`, and also less than 5.
### How do I mock methods with polymorphic return types?
Again, we can distinguish between type variables bound by the instance versus
the method. Variables bound by the instance work much the same as concrete
types, but check out the question about multi-parameter type classes for some
details.
To mock a method with a polymorphic return value bound by the method itself, the
return value must have a `Typeable` constraint. If it cannot be inferred, you
will also need to add a type annotation to the return value you set for the
method, so that GHC knows the type. If the method will be used at different
return types, you must add separate expectations to the method for each type at
which it will be used.
### Why do I need a Default instance for `mockMethod`?
`mockMethod` uses the `Default` class from `data-default` to decide what to
return when no other response is given for an expectation. If the method you
are mocking has no `Default` instance for its return type, you can use
`mockDefaultlessMethod` instead. In this case, if there's no response
specified, the method will return `undefined`.
This choice is made automatically if you derive the instances for `MockT` using
Template Haskell.
### How can I change the default behavior of mocked methods?
There are a few ways to do this:
1. To just change the default behavior, use `byDefault`. A method call must
still be expected or it will fail, but if you leave out the return value in
the expectation, this default will be used.
2. To also make unexpected calls to a method suceed, use `allowUnexpected`. If
you include a response in the argument, it will become the default in
addition to allowing an unexpected method.
3. To set up defaults for *all* users of the mock, replace your call to
`makeMockable` with a call to `makeMockableWithOptions` and set
`mockEmptySetup` to `False`. Then write an instance for `Mockable` and
implement `setupMockable` to do whatever you like. This setup will always
run before the first time HMock touches your class from any test.
### How do I stop unexpected actions I don't care about from failing my tests?
* If there is a specific method that you don't care about, use `allowUnexpected`
to ignore occurrences of that method.
* There's also a heuristic you can enable, where so-called "uninteresting"
methods are ignored. An uninteresting method is one for which no expectations
are added in the entire test. To allow these methods to succeed, use
`setUninterestingActionCheck Ignore` or `setUninterestingActionCheck Warning`.
This is similar to the behavior of gMock, which has a similar notion of
uninteresting calls.
* Finally, the biggest hammer is to use `setUnexpectedActionCheck Warning`.
This will allow any unexpected action in your test. You almost certainly
don't want to do this in your final test, but it can be useful during the
course of writing the test.
### What if there are two expectations that match the same method?
By default, the most recently added expectation is matched. Think of
expectations as being a stack, so they are first-in, first-matched. This rule
makes HMock more compositional, since you can add and satisfy expectations in a
part of your test without worrying that expectations from a larger containing
block will interfere.
There is also an option to fail when more than one expectation matches. To
enable this, just include `setAmiguityCheck True` as a statement in `MockT`.
From that point forward, ambiguous matches will throw errors.
### How do I mock multi-parameter type classes?
In order to mock a multi-parameter type class, the monad argument `m` must be
the last type variable. Then just use `makeMockable [t|MonadMPTC|]`.
### How do I mock classes with functional dependencies?
We will consider classes of the form
``` haskell
class MonadMPTC a b c m | m -> a b c
```
If you try to use `makeMockable [t|MonadMPTC|]`, it will fail. The functional
dependency requires that `a`, `b`, and `c` are determined by `m`, but we cannot
determine them for the `MockT` instance.
The recommended way to handle this case is to pass a concrete type to
`makeMockable`, like this:
``` haskell
makeMockable [t| MonadMPTC Int String Int |]
```
This will define the same `Mockable` instance for `MonadMPTC`, but the instance
for `MockT` will be defined with concrete types as required by the functional
dependency.
Note that the `MockT` instance is anti-modular, because you cannot import (even
indirectly) two different instances for `MockT` with different types in the same
module. These instances would be *incoherent*, which Haskell doesn't typically
allow. You can minimize the risk by using `makeMockable` in top-level test
modules which are never imported elsewhere. If you want to share the
expectation code, you can use `makeMockableWithOptions` and set
`mockDeriveForMockT` to `False` in your library code, and then use
`makeMockable` again in your top-level test module to define the `MockT`
instance.
If you absolutely need to write multiple tests in the same module with different
type parameters, you will need to use a wrapper around the base monad for
`MockT` to disambiguate the instances. That is a bit more involved. Here's an
example:
``` haskell
makeMockableWithOptions [t|MonadMPTC|] def {mockDeriveForMockT = False}
newtype MyBase m a = MyBase {runMyBase :: m a}
deriving (Functor, Applicative, Monad)
instance
(Monad m, Typeable m) =>
MonadMPTC String Int String (MockT (MyBase m))
where
foo x = mockMethod (Foo x)
```
### How do I test multithreaded code?
If your code uses `MonadUnliftIO` to create threads, you can test it directly
with HMock. Otherwise, you can use `withMockT` to manually inject each of your
threads into the same `MockT` block. Whichever way you do it, the expectations
are shared between threads so that an expectation added in one thread can be
fulfilled by the other.
If you don't want to share expectations, then you can use `runMockT` once per
thread to run each thread with its own set of expectations.
### How do I test code with exceptions?
You can use either the `exceptions` or `unliftio` packages to throw and catch
exceptions from code tested with `MockT`.
The behavior of `HMock` is unspecified if you continue testing after throwing
asynchronous exceptions to your threads using `throwTo`. This concern doesn't
apply to synchronous exceptions thrown with `throwIO` or `throwM`.
### How do I get better stack traces?
HMock is compatible with stack traces using `HasCallStack`. These can be very
convenient for finding out where your code went wrong. However, the stack
traces are useless unless you add a `HasCallStack` constraint to the methods of
your class. This is unfortunate, but not really avoidable with the current
state of Haskell. You can add the constraint when troubleshooting, and remove
it again when you are done.
### What should I do about orphan instance warnings?
If you have the warning enabled, GHC will usually warn about orphan instances
when you use `makeMockable`. We recommend disabling this warning for the
modules that use `makeMockable`, by adding the line
`{-# OPTIONS_GHC -Wno-orphans #-}` to the top of these modules.
Prohibiting orphan instances is just a *heuristic* to make it less likely that
two different instances will be defined for the same type class and parameters.
The heuristic works well for most application code. It does **not** work so
well for HMock, because the class you are mocking is non-test code, but the
`MockableBase`, `Mockable`, and `MockT` instances should be defined in test
code.
Since the orphan heuristic doesn't work, you must take responsibility for
managing the risk of multiple instances. The easiest way to do so is to avoid
defining these instances in libraries. If you do define instances in libraries,
you must choose a canonical location for each instance that is consistent across
all code using the library.
### Why is my method "too complex to expect with an `Action`"?
When adding an expectation, you can only use an `Action` if the method is simple
enough. Specifically, all arguments must have `Eq` and `Show` instances, and no
arguments may rely on type variables bound by the method.
If your method isn't simple enough, the solution is to add the expectation with
a `Matcher` instead of an `Action`. The arguments to `Matcher` are `Predicate`s
that can inspect the value and decide whether to match. You are now responsible
for deciding how to match the complex argument. Some options include:
1. Using a polymorphic `Predicate` like `anything`.
2. Ensuring that a `Typeable` constraint is available, and using the `typed`
predicate to cast the argument to a known type.
3. Using the `is` or `with` `Predicate`s and your own code that's polymorphic in
the type and produces a monomorphic result type you can match on.
### How do I migrate from `monad-mock`?
To mock a class with the `monad-mock` package, you will have used that library's
Template Haskell splice called `makeAction`. With HMock, you should use
`makeMockable` instead. Unlike `makeAction`, you will use `makeMockable`
separately for each class you intend to mock. The generated code is still
usable with any combination of other classes in the same tests.
Where you may have previously written:
``` haskell
makeAction ''MyAction [ts| MonadFilesystem, MonadDB |]
```
You will now write:
``` haskell
makeMockable [t|MonadFilesystem|]
makeMockable [t|MonadDB|]
```
To convert a test that uses `monad-mock` into a test using HMock, move
expectations from the list argument of `runMockT` into `expect` calls inside
HMock's `runMockT`. To preserve the exact behavior of the old test, wrap your
`expect`s with `inSequence`. You'll also need to switch from `monad-mock`'s
`:->` to HMock's `|->`, which means the same thing.
If you previously wrote (with monad-mock):
``` haskell
runMockT
[ ReadFile "foo.txt" :-> "contents",
WriteFile "bar.txt" "contents" :-> ()
]
(copyFile "foo.txt" "bar.txt")
```
You will now write this (with HMock):
``` haskell
runMockT $ do
inSequence
[ expect $ ReadFile "foo.txt" |-> "contents",
expect $ WriteFile "bar.txt" "contents" |-> ()
]
copyFile "foo.txt" "bar.txt"
```
Now that your test has been migrated without changing its behavior, you may
begin to remove assertions that `monad-mock` forced you to write even though you
didn't intend to test them. For example:
* You don't really care about the return value for `writeFile`. HMock will
return a default value for you if you leave out the `|->` operator.
* `inSequence` is overkill here, since the sequence is just a consequence of
data dependencies. (Think of it this way: if it were magically possible for
`writeFile` to be called with the right arguments but without waiting on the
`readFile`, it would be correct to do so! The order is a consequence of the
implementation, not the specification.)
Applying these two simplifications, you have a final test:
``` haskell
runMockT $ do
expect $ ReadFile "foo.txt" |-> "contents"
expect $ WriteFile "bar.txt" "contents"
copyFile "foo.txt" "bar.txt"
```
### Which GHC versions are supported?
HMock is tested with GHC versions from 8.6 through 9.4.
## Case Study: Mocking Template Haskell
As a non-trivial case study in the use of HMock, consider the problem of testing
code that uses Template Haskell. Template Haskell runs in a monad class called
`Quasi`, which provides access to actions that help build code: generating fresh
names, looking up type information, reporting errors and warnings, and so on.
While there is an `IO` instance for the `Quasi` type class, it throws errors for
most operations, making it unsuitable for testing any non-trivial uses of
Template Haskell.
As part of HMock's own test suite, the `Quasi` monad is made mockable (in
`test/QuasiMock.hs`), and then used (in `test/Classes.hs`) to test HMock's
Template Haskell-based code generation.
At first glance, this might seem unnecessary. After all, the unit tests make
use of `makeMockable` for tests of the core HMock functionality, so surely any
problems in that code that matter would cause one of the core tests to fail, as
well. However, writing these tests with mocks had two significant benefits:
1. Because Template Haskell runs at compile time, test coverage cannot be
measured. Template Haskell code at runtime generates accurate test coverage
using `hpc`. This, in turn, helped with writing more comprehensive tests.
2. Because Template Haskell errors would stop the tests from compiling, core
tests can only cover *successful* uses. Mocking `Quasi` allows tests of
Template Haskell to check the error cases, as well.
Indeed, mock `Quasi` tests were quite valuable to HMock development. First, the
initial tests revealed several places where tests did not exercise key logic:
mocking classes with superclasses, and mocking classes whose methods have rank-n
parameters. When corresponding tests were added, both of these cases turned out
to be incorrect! Next, adding tests for the error cases (which would not have
been possible to write without mocks) revealed that the code to detect mocking
classes with too many arguments was also broken, so that instead of a nice
helpful message, HMock printed something about an internal error, advising the
user to report a bug.
The implementation of the `Quasi` mock was not difficult, but there are a few
places where it was illuminating:
* Several methods of the `Quasi` type class could not be mocked by HMock because
they have polymorphic return types without `Typeable` constraints. This did
not prevent using HMock, but it did make it necessary to use a hand-written
`MockT` instance, rather than using `makeMockable` to generate everything.
* One method, `qNewName`, could have been mocked, but it wasn't the right
choice to do so. Template Haskell already provides an implementation in the
`IO` monad, which was already suitable for testing. This wasn't a problem, as
the `MockT` instance could be written to forward to the `IO` implementation.
* Certain behaviors that did need to be mocked, such as looking up `Eq` and
`Show` instances for common types, were useful for many different tests. To
help with reuse, these actions are added from `setupMockable` so they are
automatically mocked every time the class is used.
* The mocks and setup code required less than 50 lines of very straight-forward
code. There was, though, a need to write more code to derive `Lift` and
`NFData` instances for Template Haskell classes so that the correct behavior
of the mock could be implemented and tested.
All things considered, the mock of Quasi was not difficult to implement, and
improved both the experience of HMock development and confidence in its
correctness.