First time here? You are looking at the most recent posts. You may also want to check out older archives or the tag cloud. Please leave a comment, ask a question and consider subscribing to the latest posts via RSS. Thank you for visiting! (hide this)

 In my current project I'm trying to apply the best practices for building "great software" (cit.).

Beware the Rhino! by metal-dogOne of the best practices is using a (kind of) TDD approach, using Inversion of Control and Dependency Injection to test only the relevant parts of your code without testing all the layers of your applications, DB included, during each test.

Which are the benefits of this approach?

  • First of all your tests run quicker because they are not hitting the database all the times.
  • Second, you don't need to restore the initial state for the database.
  • Third, if you are working in a team with many developers, the ones that are working on the presentation layer can test their code even if the business layer or the database side of the application is not working yet.
  • Last, if your application is accessing 3rd party webservices you don't your tests to fail because of a network problem or, as it happened to me last week, if the database server dies unexpectedly.

Rhino Mocks

I decided to Ayende's Rhino Mocks to mock my layers.

At the moment I'm still in an early phase of the development, so my problem was mocking the database access layer, which is developed using a very trimmed down version of the IRepository<T> that is inside Rhino Commons.

IRepository<T> is a class that wraps NHibernate and provide a generic interface to its ISession methods.

Now let's see how to to test the Persistence Service that retrieves an User calling the IRepository<User>.

How to Mock the IRepository<T> and the Get(object) method

First I want to test the GetById method. Here a simple implementation of it:

   1:  public User GetById(int id)
   2:  {
   3:    User returnUser = _repository.Get(id);
   4:    if (returnUser == null)
   5:      {
   6:        returnUser = new UnknownUser();
   7:      }
   8:    return returnUser;
   9:  }

The Get method then calls the NH Session Get method.

And here is test that uses Rhino Mock to simulate the real IRepository<User>.

   1:  [Test]
   2:  public void CanGetUserById()
   3:  {
   4:    MockRepository mocks = new MockRepository();
   5:    IRepository<User> mockedRepository = 
   6:      mocks.CreateMock<IRepository<User>>();
   7:    User expectedUser = new User();
   8:    expectedUser.EmailAddress = "email@address.com";
   9:    expectedUser.Name = "Test User";
  10:    Expect.Call(mockedRepository.Get(666)).Return(expectedUser);
  11:    mocks.ReplayAll();
  12:    UserPersistenceService service =
  13:      new UserPersistenceService(mockedRepository);
  14:    User user = service.GetUserById(666);
  15:    Assert.AreEqual("email@address.com", user.EmailAddress);
  16:  }

Line 4: I create a new MockRepository to store all the mock object I will create and the expectations I will set on them.

Lines 5,6: I create a Mock object to mimic the behavior of our real  IRepository<User>.

Lines 7-9: I build the object what I want the mock object to return when I call the method.

Line 10: This is the most important line of the snippet. It instructs the Mock object to "Expect" a "Call" to the Get method on the mocked repository with an parameter of value 666 and, when this happens, to "Return" the object expectedUser.

Line 11: "starts" the mocked repository.

Lines 12,13: The mocked repository is "injected" inside the persistence service.

Line 14: I call the GetUserById method on the persistence service with 666 as parameter, this method calls the Get method of the repository (that is our mocked repository) which returns immediately the expectedUser without calling the real repository and hitting the DB.

Line 15: Now I can test the equality between the username of the user retrieved from the DB repository and what I expected to find.

In another post I'll write about mocking another methods of the repository, a method that accepts an array of NH Expressions. And I'll show how to extend Rhino Mock to "understand" this new type of parameter.

UPDATE: Small edit to the code of the samples after 2 suggestions from Simone Busoli.

Technorati tags: , , , ,

kick it on DotNetKicks.com

posted on Monday, June 18, 2007 11:18 PM

Comments on this entry:

# re: How to mock a NHibernate Repository

Left by Simone Busoli at 6/19/2007 9:13 AM

Good work on explaining how mocks work, I bet a lot of people yet don't get it completely.
Just to point out, however, Rhino exposes a generic interface for retrieving mocks, which IMHO is more usable in that it doesn't require a cast to the object's interface:

IRepository<User> mockedRepository = mocks.CreateMock<IRepository<User>>();

# re: How to mock a NHibernate Repository

Left by Simone Busoli at 6/19/2007 9:21 AM

...a little mistake I noticed in the code, you create a user with an EmailAddress property and then assert on a UserName property.

I liked you example however, I think it would be useful if you posted using the same example and IoC to inject the repository in the persistence service, it could be very instructive.

# re: How to mock a NHibernate Repository

Left by Simone at 6/19/2007 9:39 AM

Simone, thank you for pointing out the 2 little problems.
Actually I test on the email because in my implementation username and email must be the same, but for the purpose of the example you are e right, better to use the same property.

# re: How to mock a NHibernate Repository

Left by Ian Joyce at 6/19/2007 5:21 PM

FYI, lines 4-8 of GetById are unreachable.

# re: How to mock a NHibernate Repository

Left by Simone at 6/19/2007 5:28 PM

Ops, sorry, I forgot a return :)

# re: How to mock a NHibernate Repository

Left by Jordan at 6/19/2007 5:32 PM

Seems cool to have a Repository that hides the complexity of dealing with the ISessions of NHibernate. I tried using Rhino Commons but are too much, can you post your trimmed down version?

# re: How to mock a NHibernate Repository

Left by Simone at 6/19/2007 6:02 PM

Jordan, I'll see what I can do.
Stay tuned :)

# Rhino Mocking NHibernate Expressions

Left by CodeClimber at 6/20/2007 11:18 PM

Rhino Mocking NHibernate Expressions

# Mocking Developments

Left by Scruffy-Looking Cat Herder at 6/21/2007 12:45 PM

Mocking Developments

Comments have been closed on this topic.