Monday, 9 November 2009

Testing function parameters with Rhino Mocks

When I’m developing, often I need to test the parameters that were passed to a function.  This is most often the case when dealing with the repository pattern.

For example, if I’m writing a processor that goes through a list of objects and inserts them into the database using a repository I would wish to know that my repository is called 10 times.  I might also with to ensure that it is called 10 times in the correct order and that each time the correct object is passed into the method.

There are a few ways to do this, one way is to keep the objects in memory in my test class and assert that the correct object was passed in:

   1: IRepository repo = mocks.DynamicMock<IRepository>();
   2: mocks.ReplayAll();
   4: // testing code
   6: repo.AssertWasCalled(repo.Insert(objects[0]));
   7: repo.AssertWasCalled(repo.Insert(objects[1]));
   8: repo.AssertWasCalled(repo.Insert(objects[2]));
   9: repo.AssertWasCalled(repo.Insert(objects[3]));
  10: repo.AssertWasCalled(repo.Insert(objects[4]));
  11: repo.AssertWasCalled(repo.Insert(objects[5]));
  12: repo.AssertWasCalled(repo.Insert(objects[6]));
  13: repo.AssertWasCalled(repo.Insert(objects[7]));
  14: repo.AssertWasCalled(repo.Insert(objects[8]));
  15: repo.AssertWasCalled(repo.Insert(objects[9]));

But this isn’t going to test the order they were called in.  Also, often I find that I don’t have a reference to the object that is being passed into the method even though I might know it’s contents.

One way to get around this is to expect that when the method is called to use a delegate and add the parameters to a list we can test later.

   1: IRepository repository = mocks.DynamicMock<IRepository>();
   2: List<MyObject> args = new List<MyObject>();
   4: using (mocks.Record())
   5: {
   6:     Expect
   7:         .Call(delegate { repository.Insert(null) })
   8:         .IgnoreArguments().WhenCalled(o => args.Add(o.Arguments.First() as MyObject))
   9:         .Repeat.AtLeastOnce();
  10: }

Note the delegate, used because repository.Insert is a void method.

This way, every time the function is called the parameter is added to the list.  I can now check the order the function was called in and the contents of each parameter used each time it was called.

No comments: