When you need to verify that the code under test called a method with the expected parameters, you can mock the method with Moq and use Verify() + It.Is<T>() to check the parameters passed in. Verify() asserts that the method call happened as expected with the specified parameters.
Here’s an example. This is verifying that MessageService.Send(message) calls Repository.Save(json) when it’s a future message:
[TestMethod()]
public void TestSend_WhenFutureMessage_SavesMessageAsJsonForLater()
{
//arrange
var mockRepo = new Mock<IMessageRepository>();
var messageService = new MessageService(mockRepo.Object);
var futureMessage = new Message() { SendAt = DateTimeOffset.Now.AddDays(1) };
//act
messageService.Send(futureMessage);
//assert
mockRepo.Verify(t => t.Save(It.Is<string>(s => s.StartsWith("{"))));
}
Code language: C# (cs)
Note: It’s using a heuristic (the string starts with “{“) to determine if the string passed in is JSON or not.
In this article, I’ll show more examples of verifying parameters.
For more complex scenarios, you may want to capture the parameters and assert them directly by using the Callback() approach instead.
Table of Contents
Verify primitive parameters
This section will show a few examples of verifying primitive (int, bool, string, etc…) parameters. The examples will be mocking the following repository interface:
public interface IMessageRepository
{
public void Delete(bool cascading);
public void Save(string json);
public void InsertLog(int logId);
}
Code language: C# (cs)
Example – Hardcoded boolean value
When you’re matching an exact primitive value, you don’t need to use It.Is<T>(). You can simply hardcode the value:
//arrange
var mockRepo = new Mock<IMessageRepository>();
var messageService = new MessageService(mockRepo.Object);
var futureMessage = new Message() { SendAt = DateTimeOffset.Now.AddDays(1) };
//act
messageService.ProcessMessage(id: 1);
//assert
mockRepo.Verify(t => t.Delete(true));
Code language: C# (cs)
Example – String contains a substring
When you’re not matching exact values, you can use It.Is<T>() to examine the parameter value.
For example, let’s say you want to check if the JSON string contains the Message.Text value:
//arrange
var mockRepo = new Mock<IMessageRepository>();
var messageService = new MessageService(mockRepo.Object);
var futureMessage = new Message()
{
SendAt = DateTimeOffset.Now.AddDays(1),
Text = "Hello World"
};
//act
messageService.Send(futureMessage);
//assert
mockRepo.Verify(t => t.Save(It.Is<string>(json => json.Contains("Hello World"))));
Code language: C# (cs)
Example – Int is between two values
There are specialized methods like It.IsInRange<T>() that can simplify assertions. For example, let’s say you’re checking if an int parameter is between a range of values:
//arrange
var mockRepo = new Mock<IMessageRepository>();
var messageService = new MessageService(mockRepo.Object);
//act
messageService.ProcessMessage(10);
//assert
mockRepo.Verify(t => t.InsertLog(It.IsInRange<int>(10, 20, Moq.Range.Inclusive)));
Code language: C# (cs)
Of course, you could always use It.Is<T>() to do the same thing:
mockRepo.Verify(t => t.InsertLog(It.Is<int>(t => t >= 10 && t <= 20)));
Code language: C# (cs)
Verify one parameter while accepting any values for other parameters
When the mocked method has multiple parameters, you may only be interested in examining some of the parameters. In that case, you can use It.IsAny<T>() to accept any values for the other parameters that you’re not interested in.
For example, let’s say you’re mocking out the following repository interface and you only want to examine the json parameter:
public interface IMessageRepository
{
public void Save(int id, string json);
}
Code language: C# (cs)
Here’s how you’d do that:
//arrange
var mockRepo = new Mock<IMessageRepository>();
var messageService = new MessageService(mockRepo.Object);
//act
messageService.ProcessMessage(10);
//assert
mockRepo.Verify(t => t.Save(It.IsAny<int>(), It.Is<string>(s => s.StartsWith("{"))));
Code language: C# (cs)
This is accepting anything for the id parameter, and examining the json parameter.
Verify object parameters
This section will show examples of verifying object parameters. The examples will be mocking the following logger interface:
public interface ILogger
{
public void Info(string message, object contextData);
public void Error(Exception ex);
}
Code language: C# (cs)
Example – Object equality
When you pass an object to Verify(), it’ll first do a reference equality check.
For example, the following is verifying that the same Message reference is being passed into Logger.Info():
//arrange
var mockLogger = new Mock<ILogger>();
var messageService = new MessageService(mockLogger.Object);
var message = new Message()
{
Text = "Let's code",
SendAt = DateTimeOffset.Now.AddHours(1)
};
//act
messageService.Send(message);
//assert
mockLogger.Verify(t => t.Info("Sending message", message));
Code language: C# (cs)
If the references aren’t the same, then it’ll attempt to call Equals() (if it’s overridden).
For example, let’s say the code under test is creating a new Message object to pass to the logger:
Logger.Info("Sending message", new Message() { Text = message.Text, SendAt = message.SendAt });
Code language: C# (cs)
And Message.Equals() is overridden:
public class Message
{
//rest of class
public override bool Equals(object obj)
{
if (obj is Message msg)
{
return msg.Text == Text && msg.SendAt == SendAt;
}
else
{
return false;
}
}
}
Code language: C# (cs)
What happens when you pass the message object to Verify()?
mockLogger.Verify(t => t.Info("Sending message", originalMessage));
Code language: C# (cs)
The reference equality check fails, and it calls originalMessage.Equals(otherMessage), which returns true, making the Verify() assertion pass.
Example – Checking the object’s specific type
Let’s say you want to verify the specific exceptions that are being logged using Logger.Error(). You can use It.IsAny<T>() like this:
//arrange
var mockLogger = new Mock<ILogger>();
var messageService = new MessageService(mockLogger.Object);
var message = new Message() { Text = "Error time" };
//act
messageService.Send(message);
//assert
mockLogger.Verify(t => t.Error(It.IsAny<MessageSerializationException>()));
Code language: C# (cs)
Example – Verifying one of the object’s properties
You can use It.Is<T>() to verify one of the object’s properties. This can be useful for many reasons. For example, as a heuristic, you may want to only verify that the Message.Text property matches the expected value. Here’s how you’d do that:
//arrange
var mockLogger = new Mock<ILogger>();
var messageService = new MessageService(mockLogger.Object);
var message = new Message()
{
Text = "Let's code",
SendAt = DateTimeOffset.Now.AddHours(1)
};
//act
messageService.Send(message);
//assert
mockLogger.Verify(t => t.Info("Sending message", It.Is<Message>(m => m.Text == "Let's code")));
Code language: C# (cs)
Comments are closed.