views:

277

answers:

3

I think it's a good practise to always return empty lists or arrays instead of null when a method comes up with no results to avoid null checks in the code.

Because Rhino Mocks returns the default value for an object, which is null for lists and arrays, a lot of times I have to either add the null checks back in or setup the mocks with expectations to return lists.

Is there a way to configure or extend Rhino Mocks with this behaviour?

var repositoryMock = MockRepository.GenerateMock<ICustomerRepository>();
IList<Customer> customers = repositoryMock.getCustomers();

Assert.IsNotNull(customers);
Assert.AreEqual(0, customers.Count );
A: 

There is nothing in Rhino Mocks to automatically solve your problem. The simplest solution is to simply setup an extention/utility method for each type that uses SetupResult (or repeat.any) to configure a default value.

You could always be tricky and enumerate through members, checking for ILists / Arrays and setup the mocks dynamically - it depends on how many types you have vs how much type you could dedicate to this utility method.

Good luck!

Richard Szalay
A: 

I think changing the default behaviour of the mocks to return non-default values would be a risky move.

What would happen if your real implementations of ICustomerRepository had a bug in it so that it didn't return an empty list and instead returned a null?

If you wrote other unit tests and tested against a mock versions of the ICustomerRepository that automatically returned the empty list then you'd think that everything was OK. You might even build that code and think it would work properly, so you run your compiled app and it starts crashing.

Why? Because your classes that hit the ICustomerRepository didn't correctly handle nulls.

I would much rather be explicit and set an expectation in the test to return an empty IList from the getCustomers() method than have something "magic" happen inside the mock. Why? Because it improves readability, and the code works according to what other developers who might not be so famililar with rhino would expect it to work. i.e. a method without an expectation returns the default value.

Richard Banks
It's a valid point that the app would crash if the ICustomerRepository returned null, but that's a bug with the repository, not the classes using it. I would (hopefully :)) have unit tests for the repository to catch that problem.
Dala
I can live with a mock even more magic than they normally are :). I'd rather have them act as much as the rest of the system out of the box. Thanks for the input!
Dala
A: 

Turns out that this behaviour is possible with Moq as long as the returned object is IEnumerable. The following tests pass:

[Test]
public void EmptylListTest()
{
    var repositoryMock = new Mock<ICustomerRepository>();

    IEnumerable<Customer> customers = repositoryMock.Object.GetCustomers();

    Assert.IsNotNull(customers);
    Assert.AreEqual(0, customers.Count());
}

[Test]
public void EmptyArrayTest()
{
    var repositoryMock = new Mock<ICustomerRepository>();

    Customer[] customerArray = repositoryMock.Object.GetCustomerArray();

    Assert.IsNotNull(customerArray);
    Assert.AreEqual(0, customerArray.Length);
}

public interface ICustomerRepository
{
    IEnumerable<Customer> GetCustomers();
    Customer[] GetCustomerArray();
}
Dala