简体   繁体   中英

Mock `printfn` in F# tests

I'm trying to write a test for a small lib I'm writing that (essentially) just logs to the console.

Is there a way to mock function like this is F#?

example: in src/Lib/Lib.fs

module Lib

let print msg = printfn "Your message is: %s" msg

then, in test/LibTest/Lib.fs

module LibTest

open NUnit.Framework
open FsUnit

[<Test>]
let ``should print what I expect``() =
  print "test" |> should equal "Your message is: test"

Note: I'm aware that currently print returns unit - I am looking for a way to make assertions about what is passed to printfn (or, more ideally, what is sent to stdout, which relies less on implementation).

I've tried directly assigning a mock function to Printf.printfn to no avail (obviously, when I think about it). Is it possible to capture the output to the console? Or to mock the printfn function (it's an implementation detail, but I can live with that).

This is what I use for testing:

module StdOut =
    let stdout = System.Text.StringBuilder()
    let out (s:string) = stdout.Append s |> ignore
    let call func parm =
        stdout.Clear() |> ignore
        func parm, stdout.ToString()
    let run f p = call f p |> snd

let inline  (|>!) v f   = f v ; v
/// used to capture print outs for testing. like printfn
let printoutfn  fmt = fmt |> Printf.ksprintf (fun s -> s + "\n" |>! printf "%s"|> StdOut.out)
/// silent version of printoutfn
let printoutfns fmt = fmt |> Printf.ksprintf (fun s -> s + "\n"                |> StdOut.out)
let printout      v = printoutfn "%A" v

The code I am testing calls printoutfn or printoutfns which is the silent version.

To test the output I do it like this:

let print msg = printoutfn "Your message is: %s" msg

[<Test>] 
let ``should print what I expect``() =
      StdOut.run print "test" |> should equal "Your message is: test\n"

Notice how it includes the newline character: \\n .

There are two invocations: StdOut.call func param and StdOut.run func param the former returns the function value and the output, the latter only returns the output

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM