Alex Rivera | Logout

How to mock for testing in Haskell?

Asked 2009-06-11T23:47:23.823
37

Suppose I am defining a Haskell function f (either pure or an action) and somewhere within f I call function g. For example:

f = ...
    g someParms
    ...

How do I replace function g with a mock version for unit testing?

If I were working in Java, g would be a method on class SomeServiceImpl that implements interface SomeService. Then, I'd use dependency injection to tell f to either use SomeServiceImpl or MockSomeServiceImpl. I'm not sure how to do this in Haskell.

Is the best way to do it to introduce a type class SomeService:

class SomeService a where
    g :: a -> typeOfSomeParms -> gReturnType

data SomeServiceImpl = SomeServiceImpl
data MockSomeServiceImpl = MockSomeServiceImpl

instance SomeService SomeServiceImpl where
    g _ someParms = ... -- real implementation of g

instance SomeService MockSomeServiceImpl where
    g _ someParms = ... -- mock implementation of g

Then, redefine f as follows:

f someService ... = ...
                    g someService someParms
                    ...

It seems like this would work, but I'm just learning Haskell and wondering if this is the best way to do this? More generally, I like the idea of dependency injection not just for mocking, but also to make code more customizable and reusable. Generally, I like the idea of not being locked into a single implementation for any of the services that a piece of code uses. Would it be considered a good idea to use the above trick extensively in code to get the benefits of dependency injection?

EDIT:

Let's take this one step further. Suppose I have a series of functions a, b, c, d, e, and f in a module that all need to be able to reference functions g, h, i, and j from a different module. And suppose I want to be able to mock functions g, h, i, and j. I could clearly pass the 4 fu

Edit
Report

1 Answer

21

Why use unit testing when you can have Automated Specification-Based Testing? The QuickCheck library does this for you. It can generate arbitrary (mock) functions and data using the Arbitrary type-class.

"Dependency Injection" is a degenerate form of implicit parameter passing. In Haskell, you can use Reader, or Free to achieve the same thing in a more Haskelly way.

answered 2009-06-12T13:50:06.480

Your Answer