Posted on 3/10/2009 10:42:53 PM by Justin Etheredge
In the previous entry in this series on beginning mocking using Moq, we looked at how to create a mock and then later verify that some method was called. This is probably the most basic usage of a mocking framework, which is to simply verify a method call. One of the things that is a bit confusing when looking at a statement in a test that uses a lambda is to realize that the code you are seeing in the assertion is not actually executing. So when you see a statement like this:
mockFileWriter.Verify(fw => fw.WriteLine("1001,10.53"), Times.Exactly(1));
The lambda inside of the “Verify” method:
fw => fw.WriteLine("1001,10.53")
Is being turned into an expression tree and then analyzed by Moq, not actually being executed. Whether or not you understand what I mean by that, what you need to understand is that we are merely telling Moq what to look for, not running any code.
In order to show this a bit more clearly, what would happen if in the above code we wanted to verify that any string was passed into the “WriteLine” method, not just a particular string. Well, we simply have to call the “Verify” method like this:
mockFileWriter.Verify(fw => fw.WriteLine(It.IsAny<string>()), Times.Exactly(1));
Here you can see that we replaced the “1001,10.53” string with a method call on the static class “It”:
It.IsAny<string>())
Now it may be more obvious that this code is not being executed because it no longer looks like a simple method call. You can now see that Moq will look at this method call within the “WriteLine” method and adjust the way that it verifies this method. It will still look for exactly one call to “WriteLine” but it will accept any string passed to it, and not just the one that we had previously specified.
There are also a few other ways to verify these methods calls, such as IsRegex:
fw.WriteLine(It.IsRegex("^1001"))
Here we are matching a regex to check that the string starts with 1001. There is also one additional method called “IsInRange” which will check to see if a numerical value is within a particular range.
Verifying With Predicates
To take this a step further, we can use any predicate expression to define what we want to verify as well. For those who don’t know, a Predicate is simply a delegate that returns a boolean value. So, a variable goes in, you do some sort of check and then return a true or false. So if we wanted to check for any string that is longer than 3 characters, then we could call the “It.Is” method like this:
mockFileWriter.Verify(fw => fw.WriteLine(It.Is<string>(s => s.Length > 3)), Times.Exactly(1));
Or if we wanted to check that the string started with “1001,10.53” instead of equaling that, then we could do this:
mockFileWriter.Verify(fw => fw.WriteLine(It.Is<string>(s => s.StartsWith("1001,10.53"))), Times.Exactly(1));
There is no limit to the comparisons that we can do. We could also compare against a local variable:
string expectedValue = "1001,10.53";
mockFileWriter.Verify(fw => fw.WriteLine(It.Is<string>(s => s.StartsWith(expectedValue))), Times.Exactly(1));
This way we can keep the expected value out of the verify, making it arguably easier to read.
Property Verification
Now that you know how to verify that a method was called, what happens if we need to verify that a property was set or read? Well, it actually looks very similar to method call verification above. In order to show this, lets define a “FileName” property on the IFileWriter interface that we will set with a filename by the OrderWriter class. This is likely a poor design in a real application, but it will serve our purpose here.
So now in our OrderWriter we will do this:
public void WriteOrder(Order order)
{
fileWriter.FileName = order.OrderId + ".txt";
fileWriter.WriteLine(String.Format("{0},{1}", order.OrderId, order.OrderTotal));
}
Here we set the filename using the order id and then call the “WriteLine” method. So we will need another test:
[Fact]
public void it_should_set_the_file_name()
{
mockFileWriter.VerifySet(fw => fw.FileName);
}
This test will now only pass if something is assigned to the “FileName” property. The only problem is that we could set anything to this property, it isn’t necessarily what we want. Thankfully Moq provides a way for us to check that it was set to an exact value:
mockFileWriter.VerifySet(fw => fw.FileName = "1001.txt");
Sweet. Everything works as expected. Just as with the methods, we can match against the static “It” class like this:
mockFileWriter.VerifySet(fw => fw.FileName = It.Is<string>(s => s.StartsWith("1001")));
So as you can see, properties are just as easy to work with as methods are.
Wrap Up
In this post we have taken a look at how the verification lambdas work, and how we can use Moq to verify inexact parameter values. We have also taken a look at how we can check parameters using any predicate value. Then finally we take a look at how we can verify property values as well. In future entries in this series we will take a look at returning values, events, callsbacks, etc… So stay tuned!