Search code examples
f#mockingeasynetqfoq

Can you set up recursive mocks in foq?


I'd let to mock an IBus with Foq.

One of the methods on the IBus is OpenPublishChannel, which returns an IPublishChannel. IPublishChannel in turn has a Bus property that returns the parent IBus.

My current code is below, but obviously it doesn't compile as mockBus is not defined by the point I need it. Is there a way of setting up recursive mocking like this without creating two mocks of either interface?

open System
open EasyNetQ
open Foq

let mockChannel = 
    Mock<IPublishChannel>()
        .Setup(fun x -> <@ x.Bus @>).Returns(mockBus)
        .Create()
let mockBus =
    Mock<IBus>()
        .Setup(fun x -> <@ x.OpenPublishChannel() @>).Returns(mockChannel)
        .Create()

Solution

  • Foq supports a Returns : unit -> 'TValue method so you can lazily create a value.

    Using a little mutation instances can refer to each other:

    type IPublishChannel =
        abstract Bus : IBus
    and IBus =
        abstract OpenPublishChannel : unit -> IPublishChannel
    
    let mutable mockBus : IBus option = None
    let mutable mockChannel : IPublishChannel option = None
    
    mockChannel <-
        Mock<IPublishChannel>()
            .Setup(fun x -> <@ x.Bus @>).Returns(fun () -> mockBus.Value)
            .Create()
        |> Some
    
    mockBus <-
        Mock<IBus>()
            .Setup(fun x -> <@ x.OpenPublishChannel() @>).Returns(fun () -> mockChannel.Value)
            .Create()
        |> Some