The blog has moved to http://jessehouse.com/ ... Many google searches point here so I am leaving it operational, but there will be no new posts.

Saturday, February 16, 2008

Rhino.Mocks - the basics

Started using Rhino.Mocks recently (Awesome!!!) - just wanted to list a few of the basics; the official Rhino Mocks Documentation is very good and available here. These examples are a bit rough, they have not been compiled; there may be typos.

using
using Rhino.Mocks;

The mock repository
// use the mock repository to create the mocked objects
MockRepository mocks = new Rhino.Mocks.MockRepository();
// example
System.Object someObject = mocks.CreateMock();
// set up the behaviour you want from calls to your mocked object 
Rhino.Mocks.Expect.Call(someObject.Equals(someParameter)).Return(false);
// then don't forget
mocks.ReplayAll();
// now do stuff that calls your mocked object Equals method
...

Mock a call to the db
// create our mocked repository object - IProductRepository, the real one calls the db
IProductRepository repository = mocks.CreateMock();
// tell rhino.mocks when we call the method GetProduct with the argument 33 to return null
Rhino.Mocks.Expect.Call(repository.GetProduct(33)).Return(null);
// get the mocking ready
mocks.ReplayAll();
// pass our mock to our product service layer
ProductService service = new ProductService(repository);
// service.GetProduct makes a call to the mocked repository.GetProduct which will return null
IProduct product = service.GetProduct(33);
// should be null
Assert.IsNull(product);

Ignore any arguments
// any call to GetProduct will return null no matter the value of the arg
Rhino.Mocks.Expect.Call(repository.GetProduct(null)).Return(null).IgnoreArguments();

mock a method that returns void
IProduct product = new Product("003092", "Sierra Nevada", 6.49);
// this void call will handle our product 003092
Rhino.Mocks.Expect.Call(delegate { repository.Save(product); });
// this void call will handle any argument
Rhino.Mocks.Expect.Call(delegate { repository.Save(null); }).IgnoreArguments();

Handle multiple calls to the same method
IProduct product = new Product("003092", "Sierra Nevada", 6.49);
// note the .Repeat.Any()
Rhino.Mocks.Expect.Call(repository.GetProduct("003092")).Return(product).Repeat.Any();
// send the mock to our product service object
ProductService service = new ProductService(repository);
// find by sku calls GetProduct on the mocked Product repository
IProduct beer = service.FindBySku("003092");
// find decent beer calls GetProduct on the mocked Product repository also
IProduct decentBeer = service.FindDecentBeer();

Partial Mock
// create a partial mock with constructor args (our product repository again)
IProductService service = mocks.PartialMock(repository);
// our test case data
IUser loggedOnUser = new User("John", "Doe", CustomerType.Gold);
// mock product service calls to GetLoggedOnUser
Rhino.Mocks.Expect.Call(service.GetLoggedOnUser()).Return(loggedOnUser);
// get the mocking ready
mocks.ReplayAll();
// now GetDiscount is not a mocked method but it does call the mocked GetLoggedOnUser method
decimal discount = service.GetDiscount();
// assert the result
Assert.AreSame(44.4M, discount, "Gold customer discount not correct?");
// NOTE: this will not work (compile) unless the mocked method GetLoggedOnUser is public

5 comments:

ben.biddington said...

Hi,

Does you first example (The mock repository) work with v.3.5?

I get the error:

Invalid call, the last call has been used or no call has been made (make sure that you are calling a virtual (C#) / Overridable (VB) method).

House 9 said...

I have not tried it on 3.5 of .net but I believe it should work. Is it possible you are making multiple calls to the same mocked method? you might need a .Repeat.Any();

Anonymous said...

In 3.5 CreateMock is deprecated and should be changed to StrictMock. Might want to try that,

Anonymous said...

IProduct product = new Product("003092", "Sierra Nevada", 6.49);

Lär ju gå bra att instansiera ett interface, nötter...

House 9 said...

Had an issue with comment moderation
-------------------------------------

New Day posted this about a month ago

For the Equals method I get the same error as ben.biddington. I am using .NET 2.0
The error occurs on the line with Expect.Call so it does not proceed any further down the test.

Error
"Invalid call, the last call has been used or no call has been made (make sure that you are calling a virtual (C#) / Overridable (VB) method)."