views:

23

answers:

1

I have code under test that basically looks like this (the specific code isn't important to the question. It is just here for explanatory purposes):

public ICollection<Product> GetByCategory(string category, ISession session)
{
    return session
        .CreateCriteria(typeof(Product))
        .Add(Restrictions.Eq("Category", category))
        .List<Product>();
}

This uses method chaining (and the solution I'm looking for would also apply to fluent interface syntax).

I am not interested in finding solutions for just this specific example, I am interested in solving a more general problem. In this example, I'd like to only add an expectation for CreateCriteria. If I do this, though, I get a NullReferenceException, even if I have the CreateCriteria return a stub, because the Add method returns null.

I'd like my test to continue to work, even if additional methods are chained, or the Add method gets removed.

Is there a general trick to lowering the number of test doubles/expected calls to just the ones I want to assert against, when using method chaining?

A solution I can think of would be to make a T4 template that enumerates all methods on a type, and creates a stub with expectations that give a different default return values. But I am wondering if there are simpler options.

I am using Rhino.Mocks, but a general solution would be even more appreciated.

+1  A: 

A possible approach would be to wrap the mock object in a DynamicProxy which always returns this for the methods which are part of the fluent API and have no recorded expectations. It delegates to the normal mock object for methods for which expectations have been recorded (or are not part of the fluent interface).

Detecting which methods have expectations defined will of course be highly MockLibrary dependent. The non-fluent methods can be easily tested for using introspection.

Maybe one of the libraries has already built this in?

Peter Tillemans
Mock libraries work off objects w/ virtual functions, so you could wrap the object or interface with the DynamicProxy, rather than the mock object returned from the library, and use a mock that delegates to the base implementation when an expectation isn't set. If, of course, that option is available in the mocking library.
Merlyn Morgan-Graham