Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't there a Times.Always in Moq?

With Moq, it is possible to verify that a method is never called with certain arguments (that is, arguments satisfying certain predicates) using Times.Never.

But how to verify that, no mater how many times a method is called, it is always called with certain arguments?

The default appears to be Times.AtLeastOnce.

There is no Times.Always. Am I missing something obvious? Thanks!

Edit: I posted a suggestion to the Moq mailing list last week, but it doesn't look like it's been moderated yet. I'll post any updates here.

Edit: an example. Say I am testing a class which generates XML documents. I want to ensure that only valid documents are generated. In other words, test that the writer dependency is only ever given valid documents, with a valid sequence number, to write.

should_only_write_valid_xml_documents

Mock.Get(this.writer).Verify(
    w => w.Write(
        It.Is<XDocument>(doc => XsdValidator.IsValid(doc)),
        It.Is<int>(n => n < 3)),
    Times.Always);
like image 317
Pete Montgomery Avatar asked Jan 17 '12 16:01

Pete Montgomery


3 Answers

And how many times is 'always?' Moq keeps track of all the times a certain method is called with certain arguments, and then uses that number for comparing to Times.Never, Times.AtLeastOnce, etc.

So, if a method is executed 4 times and you set it to 'Times.Always' what does that even mean?

Times.Never would check to make sure the number is zero.

Times.AtLeastOnce would check that the number is greater than or equal to one.

Times.Always would check that the number is.... ?

You could determine the number of times it SHOULD run programmatically, then do something like:

Times.Exactly(calculatedAmount)

But there is no way for Moq to know what 'always' means.

like image 73
docmanhattan Avatar answered Nov 18 '22 19:11

docmanhattan


It sounds like you're wanting "Strict" mock behavior. If the method is called with anything other than the expected parameters, the test will fail.

This is available in Moq:

var mock = new Mock<IFoo>(MockBehavior.Strict);

(Example taken from the Moq QuickStart.)

Every invocation on the mock must now have a corresponding Setup.

Using strict mocks tends to lead to brittle tests. I would avoid this technique, or at least use it sparingly.

like image 24
TrueWill Avatar answered Nov 18 '22 19:11

TrueWill


You can apply inversion of logic to verify ALWAYS.

E.g.:

Let's say you want to do the following verification:

mock.Verify(x => x.Method(It.Is<int>(i => i == 10)), Times.Always());

you can simply replace it with:

mock.Verify(x => x.Method(It.Is<int>(i => i != 10)), Times.Never());
like image 2
Paul Avatar answered Nov 18 '22 21:11

Paul