I am trying to use Rhino.Mocks
to mock up a ControllerContext
object to gain access to runtime objects like User, Request, Response, and Session in my controller unit tests. I've written the below method in an attempt to mock up a controller.
private TestController CreateTestControllerAs(string userName)
{
var mock = MockRepository.GenerateStub<ControllerContext>();
mock.Stub(con =>
con.HttpContext.User.Identity.Name).Return(userName);
mock.Stub(con =>
con.HttpContext.Request.IsAuthenticated).Return(true);
var controller = CreateTestController(); // left out of example for brevity
controller.ControllerContext = mock;
return controller;
}
However, the HttpContext
of my mocked ControllerContext is null and there my attempts to access HttpContext.User
etc. cause a System.NullReferenceException
.
What am I doing wrong with my mocking?
The other answers have already shown how you can mock a property chain to work around your problem.
But the real problem here is that unit testing and mocking don't really work well if you violate the law of demeter. If you want your code to be testable and maximally reusable, then you need to directly inject the real dependencies of your code and hide those dependencies behind abstractions.
For example, instead of doing this:
Do this:
By introducing the
INameProvider
concept, your component code, tests and mocks become much simpler. Your code also becomes more reusable: it only has a dependency on the abstract concept of a "name provider", rather than on a bunch of ASP.NET classes. You will be able to reuse your component in any environment as long as it is possible to implement aINameProvider
adapter.The trade-off is that you will need to declare the
INameProvider
interface and write a wrapper class which implements it. When you consistently follow this approach, you will end up with a lot of small interfaces and adapter classes. Such is the way of test driven development.(In case you're wondering why I introduce
INameProvider
instead of setting the name directly - this is so that the IoC container can use the interface to match up the dependency with the implementation.)I would strongly recommend you looking at MVCContrib.TestHelper which uses
Rhino.Mocks
and provides an elegant way to test your controllers. Here's how your test might look like:And here's an unit test for a controller that is part of a sample ASP.NET MVC application I wrote.
I believe the problem is that you need to stub the whole chain of properties, or at least pass to your ControllerContext Mock a HttpContext, i.e. something along the lines of:
In your code, given that you never set the HttpContext to anything specifically, by default your Stub assumes it is null.
I haven't used the solution Darin describes, but it looks like it would make your life much easier!