Moq/moq4 — pull request #17 by quetzalcoatl (2012-06-20 13:38:40+00:00)
Title: Feature: call counts and Times.Add

This patch bases on some internal changes introduced in 'Mocking the delegates' feature.
I know the "single feature per branch" rule, but I perceive those two additions as one, because they address the same problem.

- - - - - -
The .Verify + Times.AtLeast is handy, but sometimes you just need to have some more insight on what was going on. Especially, the Times class is lacking support for checking 'incremental' calls. In some cases, it is desirable to not specify how many calls there should be, but rather, how many new calls should occur.

This patch adds a few methods that allow you to get the number of method calls, in a way similar to how the fluent Verify() is normally used.

Just as you could write:

mock.Verify( obj => obj.Foo(), Times.Exactly(4) );

now you can also:

int n = mock.Count( obj => obj.Foo() );
Assert.True( n % 3 == 0 );

- - - - - -
Additionally, this patch also includes some minor additions to the Times class

It is now possible to "offset" a 'Times' instance by a number, In but in no way this is intended to provide complex math. It is just a minor flavor that helps a little with some incremental corner cases.

var mock = new Mock<...>(....);
// do some setup that causes the Foo to be called unknown number of times
int n = mock.Count( obj => obj.Foo() );

mock.Bar(); // do the actual test that should call Foo >=3 times

mock.Verify( obj => obj.Foo(), Times.AtMost(3).Add(n) );

Offsetting is only possible in 'forward' manner. No subtracting is possible. Cases like Never/Once/Any are handled properly and intuitively, I hope:)
eg.:
(any) + 5 = (any)
(never) + 3 = (exactly:3)
(atmost:3) + 5 = (atmost:8)
(between:3..5) + 2 = (between:5..7)

Two new 'Times' members were also added, to make the Times/Add a little more flexible in certain cases:
- Times.AcceptAny - always succeeds

(acceptAny) = (atleast:0)
(acceptAny) + 3 = (atleast:3)
(acceptAny) + 5 = (atleast:5)

- Times.AcceptNone - always fails

(acceptNone) = (acceptNone)
(acceptNone) + 3 = (acceptNone)
(acceptNone) + 5 = (acceptNone)