3

None of the Mock.Expect examples I've found use Times other than 0 or 1 (never, once). I modifed one of the existing tests from Foq.Usage.fsx to attempt something that's not 0 or 1, but I can't make it work.

Does anyone see anything wrong?

let [<Test>] ``expect method is called the specified number of times`` () =
    // Arrange
    let xs = Mock.Of<System.Collections.Generic.IList<int>>()
    // Assert (setup)
    Mock.Expect(<@ xs.Contains(0) @>, never)
    Mock.Expect(<@ xs.Contains(1) @>, once)
    Mock.Expect(<@ xs.Contains(2) @>, exactly 2)
    // Act
    xs.Contains(1) |> ignore
    xs.Contains(2) |> ignore
    xs.Contains(2) |> ignore
    // Assert
    verifyAll xs
MickeyPickle
  • 103
  • 4
  • Don't do this (expects at start of test and a `verifyAll` in the Assert section) in new code! http://stackoverflow.com/questions/980554/what-is-the-purpose-of-verifiable-in-moq/1728496#1728496 – Ruben Bartelink Jan 28 '14 at 23:16
  • I don't like the expect/verifyAll style either, but if it's in Foq, it should work - unless I misunderstand how it works. – MickeyPickle Jan 28 '14 at 23:58
  • If you move the `Expect`s to the `Assert` phase, all is well. (The exception is emanating from the Act phase (the first triggering is causing it to blow if the expectation is somethign other than `once`/`atleastonce`) – Ruben Bartelink Jan 29 '14 at 00:00
  • I agree it should be possible to make it workable; my personal experience has been that Foq Just Works (and you get extreme responsiveness from Phillip Trelford thrown in too!). I'd be doing a search in the examples and/or source. But the question still remains:- what are you doing that must be expressed in this manner - I have yet to meet a case where this is a useful approach – Ruben Bartelink Jan 29 '14 at 00:04
  • If you move the `Expect`s to the `// Assert` phase, all is well. (The exception is emanating from the `// Act` phase (the first triggering is causing it to blow if the expectation is something other than `once`/`atleastonce`) – Ruben Bartelink Jan 29 '14 at 00:05
  • Ah, thank you. I've been using Foq for about ... 12 hours :) and the examples did the `Expect`s before the `//Act` and it works as long as Times is 0 or 1. Now I have 2 working versions: one using `Expect`/`verifyAll` and one using just `verify`. I prefer the explicit `verify`s - reads well. Think I should answer my own question and post them? – MickeyPickle Jan 29 '14 at 00:14
  • It def seems surprising - Phil will explain all shortly no doubt. To be honest I've zero experience with things such as `Expect` as I hit on the Don't Do That advice the very first time I tried and haven't looked back. And yes, self-answering with what worked is always good. – Ruben Bartelink Jan 29 '14 at 00:27

3 Answers3

3

This is a bug in Foq, when you use Mock.Expect it checks the expectations are met at the time of invocation on the mock. If the given expectation is not met an exception is thrown. This may in theory be useful as it gives a stack trace at the exact point that an expectation is not met.

The issue with exactly 2 is that the expectation is checked first after one invocation and it is not exactly two. In effect at invocation time we want to interpret exactly 2 as at most two, and at verifyAll as exactly two.

You can get closer to the behaviour I believe you want with the existing implementation using Mock.Expect with atmost 2 and/or a plain old verify after the effect:

let [<Test>] ``expect method is called the specified number of times`` () =
    // Arrange
    let xs = Mock.Of<System.Collections.Generic.IList<int>>()
    // Assert (setup)
    Mock.Expect(<@ xs.Contains(0) @>, never)
    Mock.Expect(<@ xs.Contains(1) @>, once)
    Mock.Expect(<@ xs.Contains(2) @>, atmost 2)
    // Act
    xs.Contains(1) |> ignore
    xs.Contains(2) |> ignore
    xs.Contains(2) |> ignore
    // Assert
    Mock.Verify(<@ xs.Contains(2) @>, exactly 2)
    verifyAll xs

Thanks for reporting the issue. The issue is now fixed in the source and will be available in the next release.

Phillip Trelford
  • 6,513
  • 25
  • 40
  • +1 Does that `.Verify` get queued for `verifyAll` to validate or is the `verifyAll` now superfluous? – Ruben Bartelink Jan 29 '14 at 08:58
  • @RubenBartelink yes, `verifyAll` is used to validate expectations set up with `expect` and `expectSeq` – Phillip Trelford Jan 29 '14 at 13:48
  • Doh, missed that bit (I wasn't seeing the `.Expect`s). The `Mock.Verify` is perfectly clear in that context. Thinking out loud [without a FSI to hand] (I wonder what'd happen if one switched the `Verify` to an `Expect` (i.e. can/should an `Expect` be able to replace a matching previous one and if so, would it be a better idea to make the code say it that way) – Ruben Bartelink Jan 29 '14 at 14:26
1

As discussed in the comments, this doesn't answer your question but ... I'd write this (which works):

let xs = Mock.Of<System.Collections.Generic.IList<_>>()
// Act
xs.Contains(1) |> ignore
xs.Contains(2) |> ignore
xs.Contains(2) |> ignore
// Assert
verify <@ xs.Contains(0) @> never
verify <@ xs.Contains(1) @> once
verify <@ xs.Contains(2) @> <| exactly 2
Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
1

Thank you, Ruben. I agree, the explicit verifys are best, but (also on your suggestion) the code below works in case anyone would want to use Expect/verifyAll.

let [<Test>] ``expect method is called the specified number of times`` () =
    // Arrange
    let xs = Mock.Of<System.Collections.Generic.IList<int>>()
    // Act
    xs.Contains(1) |> ignore
    xs.Contains(2) |> ignore
    xs.Contains(2) |> ignore
    // Assert
    Mock.Expect(<@ xs.Contains(0) @>, never)
    Mock.Expect(<@ xs.Contains(1) @>, once)
    Mock.Expect(<@ xs.Contains(2) @>, exactly 2)
    verifyAll xs
MickeyPickle
  • 103
  • 4