2

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()
ccellar
  • 10,326
  • 2
  • 38
  • 56
mavnn
  • 9,101
  • 4
  • 34
  • 52

1 Answers1

3

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
Phillip Trelford
  • 6,513
  • 25
  • 40
  • Excellent! Thank you @Phillip Trelford. Can't believe I didn't notice the unit -> 'TValue overload. – mavnn Apr 23 '13 at 11:01