Using Delegates in Rhino Mocks With the .Do Statement

I use Rhino Mocks pretty much exclusively for mocking and testing. I find that there really isn't anything that I've wanted to do that I haven't been able to figure out how to accomplish with Rhino Mocks. What is everyone else using? I'd like to know so I can take a look.

Anyway, as you know, with Expect.Call we can return property values, return values from functions, throw an error, etc. Sometimes just returning a static value isn't going to work, or it's just easier to give it some simple code to run. When you have many components, all with with their mockable interfaces, sometimes when you need to write a test that is in the middle, you need to run some simple code to test certain scenarios. I think this feature can be used inappropriately if it is overused, but it definitely has it's place when there's just no other good way to set up the test scenario.

Here is a simple example of mocking out a billing component. I admit, it's a bit contrived, but demonstrates the use of delegates in Rhino Mocks. I have an interface named IBilling that I'm mocking. It's purpose is to bill several charges that fall within a billing period. The first four Expect.Call statements simply provide a date value. The.Do statement calls a delegate that passes in a function in my testing module. When your test code hits that function call, instead of just returning a predefined value, it will execute the function you passed in.

[TestMethod] private void ChargePeriodEndsBeforeBillingPeriodDailyChargeTest {    MockRepository mocks = new MockRepository;    IBilling billing = mocks.DynamicMock;    IRateCalculator rates = mocks.DynamicMock;

   int customerId = 1;

   using (mocks.Record)    {       Expect.Call(billing.GetPeriodBeginDate)         .Return(DateTime.Parse("1/1/2010");       Expect.Call(billing.GetChargeBeginDate)         .Return(DateTime.Parse("1/1/2010");       Expect.Call(billing.GetPeriodEndDate)         .Return(DateTime.Parse("2/1/2010");       Expect.Call(billing.GetChargeEndDate)         .Return(DateTime.Parse("1/15/2010");       Expect.Call(billing.CalculateChargeDays(          new DateTime, new DateTime         .IgnoreArguments         .Do(new CalcDaysDelegate(DaysDifference));       Expect.Call(rates.GetRate(0)).Return(0.1);       Expect.Call( => billing.AddCharge(0, 0, new DateTime))         .IgnoreArguments         .Constraints(Is.Equal(customerId),                       Is.Equal(1.6),                       Is.Anything);    }    using (mocks.Playback)    {       ChargeBilling chargeBilling = new ChargeBilling(customerId, billing);         chargeBilling.AddChargeToBill;    }}

private delegate int CalcDaysDelegate(DateTime start, DateTime end); private int DaysDifference(DateTime start, DateTime end) {    TimeSpan ts = end - start;    return ts.Days + 1; }

In real life I would recommend just returning a "16" to the CalculateChargeDays function call, but a real-life scenario would be too long of a post; -) I also want to point out the use of the lambda expression for calling a function call with a void return value, => billing.AddCharge. You can also call it using the delegate keyword, but I find the lambda syntax to be cleaner and easier to read, much less easier to remember when you're coding.

Happy coding, and please let me know what you think about other mocking software you use that I might want to try.

Technorati Tags:

This article is part of the GWB Archives. Original Author: Annie Bougie

New on Geeks with Blogs

  • We Won The One Award I Actually Care About

    Full Scale made the Inc. 5000 for the fifth year straight, the 12th listing across my three companies. Here is why the one award you cannot buy is worth stopping for.

  • Your Customers Build the Features Now

    I let a tool I liked sit dead for a year rather than build the features I wanted. An MCP server meant I never had to, and your customers can do the same to your product.

  • Get the Size of a Directory in Linux the Easy Way

    du -sh for the quick answer, ncdu for the cleanup, df for the disk itself: every command for checking directory size in Linux, plus why du and df never agree.

  • Vim Search and Replace: The Ultimate Guide

    One :%s command replaces every match in a file before a find dialog would even open. The Vim substitute patterns worth the muscle memory: flags, ranges, capture groups, and multi-file edits.