views:

2061

answers:

2

I'm new to Mocking frameworks and have started using RhinoMocks to assist with my MVC App Unit Testing.

I'm using Scott Hanselmanns MVC Mock Helper to assist in mocking the HttpContext. I've succesfully (after some time) mocked some of what I need but have come unstuck when it comes to the Application property of the HttpContext.

In my application I store an object in the Application and retrieve it within a Controller like:

SomeObj foo = (SomeObj)Application["fooKey"];

This gets created on Application_Start in my MVC App.

UPDATED FOLLOWING FIRST ANSWER (additional code for clarity) Currently in the test setup I do:

HttpContextBase mockHttpBase = mocks.FakeHttpContext();
controllerToTest = new SomeController();
mocks.SetFakeControllerContext(controllerToTest);


HttpApplicationStateBase appState = 
    MockRepository.GenerateStub<HttpApplicationStateBase>();

Globals tmpAppGlobals = 
    new Globals();

mockHttpBase.Expect(ctx => ctx.Application).Return(appState);
mockHttpBase.Expect(ctx => ctx.Application[Globals.GlobalsKey]).
    Return(tmpAppGlobals);

In my unit test setup I do:

Globals tmpAppGlobals = new Globals();
controllerToTest.ControllerContext.HttpContext.
            Expect(ctx => ctx.Application[Globals.GlobalsKey]).
Return(tmpAppGlobals);

This call throws a NullReference Exception, for the Application object.

My question is two fold:

1) Is this the right approach or have I done something wrong from a design / architecture perspective?

2) Why doesn't this work?!

Thanks, in advance.

+1  A: 

Without delving too deeply, this looks mostly correct.

The Application property is virtual on HttpContextBase, so you should be able to set up a return value for it from Rhino -- Assuming you're mocking HttpContextBase as Scott Hanselmanns post does.

Some possible causes, which are really just guesses from lack of information:

  • Did you set up returns for controllerToTest.ControllerContext?
  • Did you set up a return for that objects HttpContext property?
  • Did you set up a return for that objects Application property?

The reason I ask is that typically when you do expectation setups, you already have references to the objects that will be called as part of your test, so you wouldn't do a property chain like you do with your controllerToTest.ControllerContext.HttpContext. Expect() call.

Edit:

I think I see the problem, and I think it's with this part:

Expect(ctx => ctx.Application[Globals.GlobalsKey])

I think you're assuming that indexers work the same as properties, when they don't. What you really need to do is set up an expectation on your appState object to receive a call to the Item property, like this:

// setup expectations -- assumes some of the expectations and mocks 
// the from original question
mockHttpBase.Expect(ctx => ctx.Application).Return(appState);
appState.Expect(ctx => ctx.Item(Globals.GlobalsKey)).Return(tmpAppGlobals);

// run the test
Randolpho
Randolpho, thanks. I have setup the returns for the controller context, httpContext and the application [I think]. I've added some additional code for clarity.
Lewis
Oh, I see; I didn't read the blog post completely enough.
Randolpho
Thanks again Randolpho. I couldn't get your example to work, unfortunately. I have since reverted to writing my own Mock objects for the HttpContext and child objects and am having more success doing things that way.
Lewis
+1  A: 

you could use the below for Moq. It took me awhile how to mock the HttpApplication, and the appState.Object is the return method duh!

public static HttpContextBase FakeHttpContext()
    {
        var context = new Mock<HttpContextBase>();
        var request = new Mock<HttpRequestBase>();
        var response = new Mock<HttpResponseBase>();
        var session = new FakeHttpSessionState();
        var server = new Mock<HttpServerUtilityBase>();
        var appState = new Mock<HttpApplicationStateBase>();

        context.Setup(ctx => ctx.Request).Returns(request.Object);
        context.Setup(ctx => ctx.Response).Returns(response.Object);
        context.Setup(ctx => ctx.Session).Returns(session);
        context.Setup(ctx => ctx.Server).Returns(server.Object);
        context.Setup(ctx => ctx.Application).Returns(appState.Object);

        //emulate session (HttpContext.Current.Session) 
        var contx = new HttpContext(new MyApp.NUnit.Tests.Fakes.FakeHttpWorkerRequest());
        contx.Items["AspSession"] = CreateSession();

        HttpContext.Current = contx;

        return context.Object;
    }
baskint