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