As of SVN revision 1683
, Rhino Mocks supports "recursive mocking."
Ayende discusses this feature briefly in his blog post dated 10-Oct-2008
This functionality is useful for testing code that makes successive, chained calls to an object or chain of objects. For example, recursive mocking may be useful if you were testing code like this:
string cityName = newCase.Contact.PrimarySite.PrimaryAddress.City;
Or, another example might be using the ICriteria API from NHibernate. ICriteria is an example of what's known as a "fluent interface
" or "Fluent API
." There are others like it. Rhino Mocks, for example, uses a fluent API for it's expectation and stub setup.
Consider this example using the ICriteria API from NHibernate:
IList cats = sess.CreateCriteria(typeof(Cat))
.Add( Expression.Like("Name", "Fritz%") )
.Add( Expression.Between("Weight", minWeight, maxWeight) )
Using Recursive Mocks
Please see Ayende's introductory blog post
on this subject for a usage example.
The point of recursive mocks is to prevent you from having to define an expectation for every single call in the call chain. This allows you to tell Rhino Mocks the expected call chain and it will recursively create mocks and expectations to satisfy that call chain.
Caution for Use
While this is useful functionality for specific scenarios, it should be noted that, in general, you should avoid this situation in the first place. In general, you should not need the recursive mocks functionality. Having said that, there are situations that cannot be avoided (for example, maintaining legacy code, proximity to deadlines creating change intolerance thus preventing proper refactoring,etc) and so, if all else fails, rely on this functionality so that you can at least get the code under test which is better than not testing it.
If you are able to make the proper refactorings to avoid this situation, please read the rest of this section.Edit
Law of Demeter
In the first example in the "Usage Scenarios" section above, the code violates the "Law of Demeter
" principle. Law of Demeter states that you should not go beyond one level of calls within a particular object graph. Doing so results in brittle code and drastically increases the coupling between objects, thus reducing the ease of changing the interface of one object (because other objects have too intimate knowledge of what lies beyond that object's interface). Violating Law of Demeter also creates a problem for testing since testing Object A necessarily requires you to have to know/mock Object B, C, and D. Generally, your unit tests should be focused on the "class under test" (CUT) or the immediate focus of the test and not have to mock or satisfy dependencies of objects more than one degree away from the CUT.
Recursive Mocks alleviates some of the pain inherent in testing classes with Law of Demeter violations and can thus cover up some design problems in your code, enabling you to persist in design flaws that can be far costlier later in your project's development.
Avoid Law of Demeter violations wherever possible. If unavoidable at this time or in this situation, consider using Recursive Mocks to temporarily aid in testing and make a note to correct the matter later.Edit
Complex and/or Fluent Interfaces
The other example demonstrated above is the ICriteria fluent interface. Other examples of complex interfaces may be the ADO.NET API (IDbConnection, IDbCommand, IDataReader, and the various other interfaces) and the ASP.NET API (HttpContext, HttpRequest, etc).
In general, you should seek to wrap complex API's that your application uses with a simplified interfaces (one or more depending on context and usage patterns) that are more applicable and specialized to your situation. This helps to create an abstraction and break specific dependencies on specific frameworks (i.e. NHibernate, ADO.NET, etc) to allow for adaptability later on, as well as making it easier to test your components without necessarily having to drag the entire ICriteria or ADO.NET API into your tests.
These adapters or wrappers should be necessarily light, have very little logic and generally be pass-through's-with-conventions and require little to no unit testing and only integration-level testing.
Avoid mocking complex API's as this will tend to lead to specific behavior and assumptions cropping up in tests that don't necessarily behave or match with the ACTUAL behavior or assumptions of the ACTUAL API. This could result in your tests passing using the mocked API, but failing critically when run against the actual/live API.
Recursive Mocks alleviates some of the pain involved with mocking complex APIs which may make it easier for you to get into the situation described above (mocked API behavior differing from the actual API behavior).
Avoid mocking these APIs directly. However, if the situation is currently unavoidable for whatever reason, prefer using Recursive Mocks to ensure that the code gets at least some testing and make a note to correct the matter at a later, more opportune date.