I'm having difficulties to Mock Microsoft ILogger with Foq.
module MockExample
open Microsoft.Extensions.Logging
open NUnit.Framework
open Foq
//open Foq.Linq
// Implementation
type Worker (logger:ILogger) =
member this.DoSomething (ok:bool) =
if ok then
logger.LogInformation("success 1")
else
logger.LogError("error 1")
// Test file
[<Test>]
let ``When error should log error`` () =
// 1. let logger = Mock<ILogger>().SetupAction(fun lg -> lg.LogError("error")) ...Create() not availabe
// 2.
//let loggerMock = Mock<ILogger>();
//loggerMock.SetupFunc(fun lg -> lg.LogError(It.IsAny<string>())) |> ignore // .Returns() is not usable
//let logger = loggerMock.Create()
let logger = mock()
// act
Worker(logger).DoSomething(false)
verify <@ logger.LogError("error 1") @> once
//verify <@ logger.LogError("success 1") @> never
Test does not pass.
I tried also other syntax to try to "mimic" the LogError signature but withut cuccess.
As sugegsted I'm trying to mock the real logger method .Log(logLevel, message, ...)
, but still not able to get it working:
Essentially I don't know how to mock this:
member Log<'TState> : logLevel: LogLevel * eventId: EventId * state: 'TState * ``exception`` : exn * formatter: System.Func<'TState,exn,string> -> unit
to extract/register/compare the state
(it contains the log "message").
As a workaround, I wrote my mock of the ILogger and it serve the purpose, but my question is still "how to do it with Foq" ?
type LoggerMock () =
let mutable informations:string list = []
let mutable errors:string list = []
member this.LoggedInformations = informations
member this.LoggedErrors = errors
interface ILogger with
member this.Log(logLevel: LogLevel, eventId: EventId, state: 'TState, ``exception``: exn, formatter: System.Func<'TState,exn,string>): unit =
match logLevel with
| LogLevel.Information -> informations <- informations @ [state.ToString()]
| LogLevel.Error -> errors <- errors @ [state.ToString()]
| _ -> ()
member this.BeginScope(state: 'TState): System.IDisposable =
raise (NotImplementedException())
member this.IsEnabled(logLevel: LogLevel): bool =
raise (NotImplementedException())
[<Test>]
let ``When error should log error (custom mock)`` () =
let logger = LoggerMock()
Worker(logger).DoSomething(false)
logger.LoggedErrors |> should contain "error 2"
The problem is that .LogError and .LogInformation are not actually methods on ILogger, but extension methods that wrap the log method that ILogger actually defines.
The method you need to mock is: ILogger.Log Method
I believe the extension methods all call that one method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With