Justin Saret’s incongruous thoughts

What’s been playing on my mind lately is…

Unit Testing object parameters using Rhino Mock Constraints

Posted by saret on October 6, 2007

Normally when unit testing and using a mock framework like Rhino one tests the interaction style of the method under test with it’s dependencies by generating mocks with Rhino in our code. This allows testing that the mock dependencies’ methods were used as we expect them to be, however testing the object passed to the mock as a parameter is often necessary. This often happens when the method under test either has to construct the object, the object is passed into the method or obtained from another mocked dependency such as a repository and especially when the objected (however it gets into the class under test) is changed prior to being passed as a parameter.

Rhino mocks offers a couple of ways that allow us to do this. Which method you should use often depends on your requirements on how you need to test the parameter.

This example (don’t judge it’s architecture/code as it’s just that – an example, that might not compile as this post was done in a text editor) concerns a controller that sends a generic email message to a list of addresses. For simplicity I’ve ignore any view or email address object, which would require more code to show a proper test for this example as well as null/empty checks on parameters. In this example I’ll be passing the data directly into a method of the email controller, then constructing an email message object (forgetting that email address might be an object) and passing it to a email sender interface (mocked).

The actual code might be roughly like this:

public class EmailController
{
    private IEmailGateway _gateway;

    public EmailController(IEmailGateway gateway)
    {
        _gateway = gateway;
    }

    public void SendMessageToRecipients(IList emailAddresses, string message)
    {
        EmailMessage message = new EmailMessage(emailAddresses, message);
        _gateway.SendEmail(message);
    }
}

Probally easiest way to test the parameter passed is when you can construct and compare an EmailMessage in your test. This would lead to test code such as this:

[Test]
public void TestThatMyMethodPassesTheRightData()
{
    List recipients = { “bob@x.com, james@y.com, peter@p.com”};
    string message = “This is auto generated”;
    EmailMessage expectedMessage = new EmailMessage(recipients, message);
    
    MockRespository mockRepo = new MockRepository();
    IEmailGateway gateway = mockRepo.CreateMock();
    
    EmailController testController = new EmailController(gateway);
    
    using(mockRepo.Record())
    {
        gateway.SendEmail(null);
        LastCall.Constraint(Is.Equal(expectedMessage));
    }
    using(mockRepo.PlayBack())
    {
        testController.SendMessageToRecipients(recipients, message);
    }
}

Sometimes though one isn’t able to directly compare an object using the Equals method as the passed object might be different on every construction (even though the constructor parameters are the same). For example this can occur due to possibly autogenerated numbers/Guids in the passed objects constructor.
In this case, one needs to be able to test the object’s state such as via it’s properties. While there are a couple of ways of doing this, one way I tend to use is like this:

[Test]
public void TestThatMyMethodPassesTheRightData()
{
    List recipients = { “bob@x.com, james@y.com, peter@p.com”};
    string message = “This is auto generated”;

    Predicate constraint = delegate(EmailMessage msg)(
        { return (msg.Recipients == recipients) && (msg.Message == message); });
    
    MockRespository mockRepo = new MockRepository();
    IEmailGateway gateway = mockRepo.CreateMock();
    
    EmailController testController = new EmailController(gateway);
    
    using(mockRepo.Record())
    {
        gateway.SendEmail(null);
        LastCall.Constraint(Is.Matching(constraint));
    }
    using(mockRepo.PlayBack())
    {
        testController.SendMessageToRecipients(recipients, message);
    }    
}

This technique utilizes an anonymous delegate/closure so one can keep the declaration of the predicate within the test method itself. While this is shown using c# 2, the code is even more compact/cleaner using some other languages such as c# 3′s lambda expressions, or Boo’s closure syntax. for example in Boo one can write the predicate like this:

constraint = {msg as EmailMessage | msg.Recipients == recipients && msg.Message == message}

Sometimes though one might need to test multiple calls to a mocked dependancy, with each call having a different parameter.
If the EmailController’s method’s was writing like the following code then this would be the case

public void SendMessageToRecipients(IList emailAddresses, string message)
{
    foreach(string recipient in emailAddresses)
    {
        EmailMessage message = new EmailMessage(recipient, message);
        _gateway.SendEmail(message);
    }
}

For the following I’m assuming that one would be interested in testing this in an ordered manner, even though in reality one probally wouldn’t be that interested in the order of calls for this method.
The test method for equals would look like this:

[Test]
public void TestThatMyMethodPassesTheRightData()
{
    List recipients = { “bob@x.com, james@y.com, peter@p.com”};
    string message = “This is auto generated”;
    EmailMessage expectedMessage1 = new EmailMessage(“bob@x.com”, message);
    EmailMessage expectedMessage2 = new EmailMessage(“james@y.com”, message);
    EmailMessage expectedMessage3 = new EmailMessage(“peter@p.com”, message);
    
    MockRespository mockRepo = new MockRepository();
    IEmailGateway gateway = mockRepo.CreateMock();
    
    EmailController testController = new EmailController(gateway);
    
    using(mockRepo.Record())
    {
        using(mockRepo.Ordered())
        {
            gateway.SendEmail(null);
            LastCall.Constraint(Is.Equal(expectedMessage1));
            
            gateway.SendEmail(null);
            LastCall.Constraint(Is.Equal(expectedMessage2));
            
            gateway.SendEmail(null);
            LastCall.Constraint(Is.Equal(expectedMessage3));
        }
    }
    using(mockRepo.PlayBack())
    {
        testController.SendMessageToRecipients(recipients, message);
    }
}

The code can also be wrapped up in a loop if required within the ordered area (using a List to store the expected messages).

If however we can’t use the Equals constraint, one could do this using the predicate option. While one can just define multiple
predicates for this purpose, one technique I’ve been using in my newest pet project (built using Boo) is to define the preditate
once, but use currying to vary it for each constraint such as like this:

delegate Predicate constraint(string address);
[Test]
public void TestThatMyMethodPassesTheRightData()
{
    List recipients = { “bob@x.com, james@y.com, peter@p.com”};
    string message = “This is auto generated”;

    Constraint constraint = delegate(string address)(
        {
            return delegate(EmailMessage msg)
                {
                    return (msg.Recipients == address) && (msg.Message == message);
                };
        });
        
    MockRespository mockRepo = new MockRepository();
    IEmailGateway gateway = mockRepo.CreateMock();
    
    EmailController testController = new EmailController(gateway);
    
    using(mockRepo.Record())
    {
        using(mockRepo.Ordered())
            {
                gateway.SendEmail(null);
                LastCall.Constraint(Is.Matching(constraint(recipients[0])));
                
                gateway.SendEmail(null);
                LastCall.Constraint(Is.Matching(constraint(recipients[1])));
                
                gateway.SendEmail(null);
                LastCall.Constraint(Is.Matching(constraint(recipients[2])));
            }
    }
    using(mockRepo.PlayBack())
    {
        testController.SendMessageToRecipients(recipients, message);
    }    
}

Again this looks alot better using Boo’s syntax. The constraint could be defined like this without the delegate definition:

constraint = def(address):
    return {msg as EmailMessage | msg.Recipient == address & msg.Message == message }

This technique also allows you to wrap all the expected and lastcall lines up in a loop if required.
Jeffrey Palermo presents another method on doing this that I found before finishing this post.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.