Given i have the IO function:
// this can either be IO or some other side effect
//that makes the function less pure
printf "HI"
I want to test that IO was called correctly. An imperative solution for testing that IO was called correctly would be to wrap the IO statement in an object, mock the object, pass the object in using dependency injection, and verify the correct method was called with the correct parameters. I wonder if instead of using dependency injection to test F#, a better way would be checking the output of the function (by asserting that the correct value or function is returned) and stub out the IO call; therefore making the function pure again by eliminating the side effect of an IO call.
I am considering wrapping all IO in a special module like so.
let MyPrint print statement = print statement ; statement
so that i can stub out the IO function and assert in my tests that the correct operation occurred like so:
code under test:
let PrintHi = fun(print) -> MyPrint print "HI"
let DoNothing = fun(print) -> ()
let DoIf conditional =
if conditional then PrintHi
else DoNothing
FsUnit:
[<Test>] member test.
let printStub value = ()
``Test Hi Is Printed When TRUE`` ()=
let testedFunc = DoIf true
testedFunc(printStub) |> should equal PrintHi(printStub)
Is this a good way to test IO side effects? Is there a better way? Please keep in mind that my goal is to test any IO, not just a print statement.
Generally speaking, you’ll want to separate pure code from impure (side-effecting) code; and keep code as pure as possible.
I recommend reading these articles about it, they’re written for other functional languages but the code they use is simple and the concepts are well explained and can be easily applied in F# (and many other languages for that matter):