Don't mock HttpContext

Posted by Joe Wilson on Thursday, August 19, 2010 6:40 PM

He doesn't like to be mocked!crying kid

It's so easy to take a direct dependency on HttpContext and not even realize it.  If you're in the code behind in Web Forms or in a controller action in MVC, it's just right there, tempting you to use it to access session variables, application security, etc.

But don't.

Some little known facts about HttpContext:

  • HttpContext is the largest object ever created by humans.
  • If you printed out the code for everything in HttpContext, the pages could be stacked end to end to wrap around the Earth's equator 7 times.
  • Mocking HttpContext is like trying to calculate the last digit of pi.  There is always a little more to it. 
  • Chuck Norris gave up trying to mock HttpContext.  He was deep in HttpContext.Response and quit, curled into a ball on the floor, and started whimpering.

Sealed what?  Object reference what?

Let's say you've got some MVC security stuff you're trying to work with in a controller action.  You've got code like:

    public class OrderController : Controller
    {
        [Authorize]
        public ActionResult Process()
        {
            if (User.IsInRole("Admin"))
            {
                return View("SecretAdminStuff");
            }

            return View("NotAuthorized");
        }
    }

See that User.IsInRole() code?  That call is really to HttpContext.Current.User.IsInRole().  You just took the bait and are tied to HttpContext now.

So what? You have to use HttpContext to get that information, right?  Sure, but you don't want to be tied directly to it or you've created untestable code.

Let's try a couple tests to verify the branching in this action method is returning the correct view based on the user's role.  I'm using NUnit, Rhino Mocks, and the Should assembly below.  Rhino Mocks has .Stub() and .Return() extension methods to set the expected return values for whether the user is or isn't in the Admin role.

        [Test]
        public void Should_return_NotAuthorized_view_when_not_Admin_user()
        {
            // Arrange
            var mockContext = MockRepository.GenerateMock<HttpContext>();
            mockContext.Stub(x => x.User.IsInRole("Admin")).Return(false);
            var orderController = new OrderController();

            // Act
            var result = orderController.Process() as ViewResult;

            // Assert
            result.ViewName.ShouldEqual("NotAuthorized");
        }

        [Test]
        public void Should_return_SecretAdminStuff_view_when_Admin_user()
        {
            // Arrange
            var mockContext = MockRepository.GenerateMock<HttpContext>();
            mockContext.Stub(x => x.User.IsInRole("Admin")).Return(true);
            var orderController = new OrderController();

            // Act
            var result = orderController.Process() as ViewResult;

            // Assert
            result.ViewName.ShouldEqual("SecretAdminStuff");
        }

As soon as we run the tests we see "System.NotSupportedException : Can't create mocks of sealed classes".  Oh yeah, HttpContext is sealed.  That won't work.

Hmmm.  Aren't there some new classes in System.Web.Abstractions for just this kind of thing?  Let's change HttpContext

var mockContext = MockRepository.GenerateMock<HttpContext>();

to HttpContextBase

var mockContext = MockRepository.GenerateMock<HttpContextBase>();

and see if that helps.

The new problem is: "System.NullReferenceException : Object reference not set to an instance of an object."  Mocking HttpContextBase isn't helping because the test isn't passing the mock context into the controller.  Every call in the action method to User.IsInRole() will always call the real HttpContext, which isn't created because the test is not running in the ASP.NET process.

You can get around this with Typemock Isolator, which goes beyond mocking and can intercept the next call to HttpContext.Current.User.IsInRole() and swap out a result, but isn't there a simpler way to do this without buying another product or waiting for better abstract classes to work with?

A better way

We can't test something tied to HttpContext like this.  We need another approach.  The one I favor is wrapping the calls we care about, delegating out to the untestable code in the wrapper class, then passing an interface to the wrapper class into the constructor of the class using it.

Here's the wrapping class I've created to access a few HttpContext current user values and the interface for the wrapping class:

    public class CurrentUser : ICurrentUser
    {
        public virtual string Name()
        {
            return HttpContext.Current.User.Identity.Name;
        }

        public bool IsLoggedIn()
        {
            return HttpContext.Current.User.Identity.IsAuthenticated;
        }

        public bool IsGuest()
        {
            return HttpContext.Current.User.IsInRole("Guest");
        }

        public bool IsAdmin()
        {
            return HttpContext.Current.User.IsInRole("Admin");
        }
    }

    public interface ICurrentUser
    {
        string Name();
        bool IsLoggedIn();
        bool IsGuest();
        bool IsAdmin();
    }

Now I need to update the controller to inject this dependency into the constructor so it can be mocked, and use a private field set in the constructor for subsequent calls to _currentUser:

    public class OrderController : Controller
    {
        private readonly ICurrentUser _currentUser;

        public OrderController(ICurrentUser currentUser)
        {
            _currentUser = currentUser;
        }

        [Authorize]
        public ActionResult Process()
        {
            if (_currentUser.IsAdmin())
            {
                return View("SecretAdminStuff");
            }

            return View("NotAuthorized");
        }
    }

Now we've got a testable action method.  I mock the CurrentUser with MockRepository.GenerateMock<ICurrentUser>, set its return value with the Rhino Mocks .Stub() and .Return() extension methods, and check for the expected results:

        [Test]
        public void Should_return_NotAuthorized_view_when_not_Admin_user()
        {
            // Arrange
            var mockCurrentUser = MockRepository.GenerateMock<ICurrentUser>();
            mockCurrentUser.Stub(x => x.IsAdmin()).Return(false);
            var orderController = new OrderController(mockCurrentUser);

            // Act
            var result = orderController.Process() as ViewResult;

            // Assert
            result.ViewName.ShouldEqual("NotAuthorized");
        }

        [Test]
        public void Should_return_SecretAdminStuff_view_when_Admin_user()
        {
            // Arrange
            var mockCurrentUser = MockRepository.GenerateMock<ICurrentUser>();
            mockCurrentUser.Stub(x => x.IsAdmin()).Return(true);
            var orderController = new OrderController(mockCurrentUser);

            // Act
            var result = orderController.Process() as ViewResult;

            // Assert
            result.ViewName.ShouldEqual("SecretAdminStuff");
        }

Hey, wait a sec.

If you're thinking to yourself: I've just tested the code in the action method and not whether HttpContext really works, you're exactly right.  The tests should cover the branching in the controller action and are unit tests.  They are not integration tests that check to see if HttpContext is returning the right values.

I'm OK with that tradeoff.  I know HttpContext works.  It's been around forever and it's in a System.<something> namespace, so I shouldn't be testing it. 

The real question is, do my login and roles and authorization settings work as expected in my application.  That calls for integration testing, and the easiest way to do that is click through those screens and see if it's working.  You can also automate this clicking around with Watin, or SpecFlow (which uses Watin internally to drive the browser).

Tags: , , , , , , ,
Categories: Technical


kick it on DotNetKicks.com shout it on DotNetShoutOut

Unit testing untestable code

Posted by Joe Wilson on Tuesday, April 6, 2010 1:44 PM

Let’s say you’ve got a static or sealed class, or a class with non-virtual members that your code needs to use.  You need to unit test your code, but you can’t get an instance of this class and/or you can’t mock it. 

There are two ways to go:

  1. Buy a tool that let’s you mock things like this, such as Typemock Isolator or the newly announced Telerik JustMock.
  2. Code around it.

Buy it

I’ve already compared Typemock Isolator ($799) to RhinoMocks (free).  Typemock Isolator works as advertised.  The biggest issue is the price.  It’s hard enough to get management approval for introducing external tools.  But when buy-in literally means BUY in, it’s even harder.

Build it

Don’t despair if you’re stuck with “code around it” and using free mocking tools!  If you can change the code that is static, sealed, private, non-virtual, etc. fix it that way.  That’s the best thing.

But if it’s in a legacy assembly you have to use, and you can’t just change the original code, use this simple technique. 

Here’s the untestable class we need to use.  It’s static, so we can’t mock an instance of it with Rhino Mocks.

public static class StaticSendOrderClass
{
    public static void SendOrderToAccountsPayable(Order order)
    {
        // Pretend code here...
    }
}

Here’s the new code you’re working on that uses this static class to process an order:

public class OrderProcessor
{
    public void ProcessTheOrder(Order order, bool useStaticClass)
    {
        if (useStaticClass == true)
        {
            StaticSendOrderClass.SendOrderToAccountsPayable(order);
        }
        else
        {
            // Notify accounts payable some other way
        }
    }
}

First, we need to create an interface with just the functionality we need from the untestable class.  Name the class and method(s) whatever makes sense for your app.  You’re not tied to the legacy code naming convention; this is your code now.

public interface INotifyAccountsPayable
{
    void SendOrder(Order order);
}

Next, create a new class to implement this interface and wrap the untestable code.  In the method calls in the new class, turn around and delegate the call to the untestable class.

public class NotifyAccountsPayable : INotifyAccountsPayable
{
    public void SendOrder(Order order)
    {
        StaticSendOrderClass.SendOrderToAccountsPayable(order);
    }
}

Now inject the new interface into the constructor of your new class as an argument.  You’ll also want to create a private field and set its value to the instance argument in the constructor.  Now you can swap out your old code that calls the untestable code, and instead use your new private field.

public class OrderProcessor
{
    private readonly INotifyAccountsPayable _notifyAccountsPayable;

    public OrderProcessor(INotifyAccountsPayable notifyAccountsPayable)
    {
        _notifyAccountsPayable = notifyAccountsPayable;
    }

    public void ProcessTheOrder(Order order, bool useStaticClass)
    {
        if (useStaticClass == true)
        {
            _notifyAccountsPayable.SendOrder(order);
        }
        else
        {
            // Notify accounts payable some other way
        }
    }
}

Now you’ve got a unit testable OrderProcessor class!  Mock the INotifyAccountsPayable interface with Rhino Mocks and inject that mocked dependency into your class under test.  Then you can verify the call was made as expected.

[Test]
public void Should_call_untestable_code_when_useStaticClass_is_set_to_true()
{
    // Arrange
    var mockNotifyAccountsPayable = MockRepository.GenerateMock<INotifyAccountsPayable>();
    var orderProcessor = new OrderProcessor(mockNotifyAccountsPayable);
    var stubOrder = MockRepository.GenerateStub<Order>();
    var useStaticClass = true;

    // Act
    orderProcessor.ProcessTheOrder(stubOrder, useStaticClass);

    // Assert
    mockNotifyAccountsPayable.AssertWasCalled(x => x.SendOrder(stubOrder));
}

Please note this is not testing the internals of the untestable, static code.  But you don’t need to worry about unit testing the internals of that code.  You don’t own that code.  Testing that is really an integration test, not a unit test.  Using this approach, you isolate your new code from an external dependency and keep all your new code testable.

Tags: , ,
Categories: Technical


kick it on DotNetKicks.com shout it on DotNetShoutOut

Presentation: Unit Testing and Mocking with NUnit and Rhino Mocks

Posted by Joe Wilson on Sunday, February 28, 2010 2:57 PM

Thanks to the folks who came out for my talk on unit testing and mocking with NUnit and Rhino Mocks at the Rocky Mountain Tech Trifecta.  I really appreciate all the comments and questions.  I was also really stoked to hear it helped some of you get over that unit testing hurdle.

The slides and code can be downloaded here.

Tags: , ,
Categories: Presentations


kick it on DotNetKicks.com shout it on DotNetShoutOut

Specifying Args with Rhino Mocks

Posted by Joe Wilson on Wednesday, November 25, 2009 4:33 PM

The problem

I ran into a snag testing some code today with Rhino Mocks.  I was mocking calls to a repository and inspecting the repository method calls and arguments passed.

Everything started off pretty normal with the repository dependency injected into the class under test:

// Arrange
var repository = MockRepository.GenerateMock<ICustomerRepository>();
var passenger = new Passenger(repository);

// Act
passenger.CallTheMethodUnderTest(arg1, arg2);

In my Assert section, I needed to check that the correct repository methods were called with the correct arguments.  The catch was, one of the arguments was a class created within the method under test.  I thought I could create and assert the equivalent Customer in my test like this:

// Assert
var expectedCustomer = new Customer
                           {
                               CustomerID = "1234",
                               FirstName = "Joe",
                               LastName = "Wilson"
                           };
repository.AssertWasCalled(x => x.SomeRepositoryMethod(
    arg1, 
    arg2, 
    expectedCustomer));

The two Customer objects (in the test and in the method under test) had the same values, but of course, were not the same objects.  They were two different Customer objects that happened to have the same values.  So Rhino Mocks told me that my expected Assert wasn't met.

The answer

I knew Rhino Mocks could ignore arguments with

Args<T>.Is.Anything

But I knew what the values should be.  In fact, for this test, the values being passed into the repository calls were just as important as the calls themselves.

So I tried comparing the values of the two Customer objects instead of the objects themselves:

repository.AssertWasCalled(x => x.SomeRepositoryMethod(
    arg1,
    arg2,
    Arg<Customer>.Matches(c => 
        c.CustomerID.Equals("1234") &&
        c.FirstName.Equals("Joe") &&
        c.LastName.Equals("Wilson"))));

So close!  But now Rhino Mocks told me if I used Arg for one parameter, I'd better use it for all of them.  No biggie. I made the change and this worked:

repository.AssertWasCalled(x => x.SomeRepositoryMethod(
    Arg<int>.Is.Equal(arg1),
    Arg<int>.Is.Equal(arg2),
    Arg<Customer>.Matches(c => 
        c.CustomerID.Equals("1234") &&
        c.FirstName.Equals("Joe") &&
        c.LastName.Equals("Wilson"))));

Postmortem

The Arg statement let's you specify a type and tell Rhino Mocks you don't know or don't care about the value:

Args<int>.Is.Anything

You can also tell Rhino Mocks you know the type and what the value should be:

Args<int>.Is.Equal(7)

If you have a non-primitive type or complex assert, you can also inspect values with the Matches statement:

Arg<Customer>.Matches(c => 
    c.CustomerID.Equals("1234") &&
    c.FirstName.Equals("Joe") &&
    c.LastName.Equals("Wilson"))));

I realize the code in these tests is probably way too familiar with the code under test.  I prefer testing state over this kind of interaction testing where possible.  But this was a case where the code under test had a void return and didn't do much besides parse some values and call repository methods based on those values.

In times like this, I'm glad I have interaction testing to fall back on so I can verify my code is behaving the way it should.

Tags: ,
Categories: Technical


kick it on DotNetKicks.com shout it on DotNetShoutOut

Comparison of Typemock Isolator and Rhino Mocks

Posted by Joe Wilson on Thursday, October 15, 2009 12:55 PM

I just started a new project using Typemock Isolator.  It's a new tool for me, and since I've mostly used Rhino Mocks, my learning is from the perspective of "how do you do this with Rhino Mocks".  These are the differences I see so far.

General

  • Typemock Isolator is a commercial product.  Rhino Mocks is free and open source.  Here's the Typemock pricing.
  • Typemock Isolator can mock just about anything, including not normally mockable things like private methods, static methods, and sealed classes.  Rhino Mocks has traditional mocking from an interface, abstract class, etc.  There has been some hand-wringing about whether or not Typemock was too powerful and encouraged untestable software designs.  But I think it's uncommon to create a brand-new stand-alone project, at least in enterprise development.  So you're probably dealing with at least some code that wasn't written with testing in mind.  You can wrap those static classes and create new default constructors and all kinds of OO jujutsu.  Or you can just leave it alone and mock it as-is with Typemock.
  • With Typemock Isolator, everything starts with "Isolate" call.  That's hard to beat for simplicity and discoverability.  You can also use the AAA style syntax.  Rhino Mocks also has AAA style testing in the newer versions.  But there has been some confusion (at least in my mind) over the main entry points, like MockRepository.GenerateMock<ISomeClass>() and MockRepository.GenerateStub<ISomeClass>().  Once you understand it, you're all set, but it's kind of a stumbling block for people new to Rhino Mocks.

OK, let's move on to other syntax differences.  I grouped these by AAA style (arrange, act, assert).  Since the "act" step should be invoking your system under test, the frameworks should look the same there.  They differ in the setup syntax (arrange) and the verify syntax (assert).

Arrange Syntax

Simple mocking

For simple mock objects, Typemock uses this syntax:

// Arrange
var repository = Isolate.Fake.Instance<IContactRepository>();
var contact = new Contact(repository);

// Act
contact.DoSomethingThatUsesARepository();

as compared to the Rhino Mocks syntax:

// Arrange
var repository = MockRepository.GenerateStub<IContactRepository>();
var contact = new Contact(repository);

// Act
contact.DoSomethingThatUsesARepository();

Not much here.  Just different ways to do the same thing.

Argument handling

Method call arguments are ignored by default in Typemock, so you don't have quite as much setup to get to the system under test.  You still need to put the correct type in the argument, but it can be null, string.Empty, 0, etc.

With Rhino Mocks, you have to be explicit when arguments don't matter:

theClass.Expect(x => x.theMethod(null)).IgnoreArguments();

or you can use the newer, more readable but maybe more typing Rhino Mocks syntax:

theClass.Expect(x => x.theMethod(Arg<theArgument>.Is.Anything));

In Typemock, you use this syntax:

Isolate.WhenCalled(() => theClass.theMethod(theArgument)).WithExactArguments();

only if the arguments are important to you.

So you can ignore arguments or use specific arguments with either framework.  They differ on the default setting.

Unmockable mocking

In Typemock, you can also ignore calls on "live" methods (real instances, not fakes, stubs, or mocks) with:

Isolate.WhenCalled(() => theClass.theMethod(theArgument)).IgnoreCall();

The only way to not call into live code with Rhino Mocks that I'm aware of is to use a stub.  This is the traditional testing approach that injects a stubbed dependency into the class under test. 

So let's assume I need to test a Contact class method that does some stuff and then sends an email using EmailService, but I don't want an email to actually go out.  Here's the Typemock arrange and act:

// Arrange
var emailService = new EmailService();
var contact = new Contact(emailService);
Isolate.WhenCalled(() => emailService.SendContactInfoToSales(contact)).IgnoreCall();

// Act
contact.DoSomethingThatSendsAnEmail();

And the Rhino Mocks arrange and act:

// Arrange
var emailService = MockRepository.GenerateStub<IEmailService>();
var contact = new Contact(emailService);

// Act
contact.DoSomethingThatSendsAnEmail();

For the Rhino Mocks approach, my EmailService has to be mockable.  Again, you can write code to do that, and in this sample I am using an interface to EmailService to do that.  But with Typemock, you just tell the test to ignore that call.  You don't need to write more code to make the EmailService test-friendly. 

Suppose EmailService is in some company-owned assembly you have to use and it's a sealed class.  Yes, you can wrap it with an interface, but why not just tell it to skip email sending with Typemock.  That's pretty powerful.  You can focus on the new code you want to test instead of refactoring existing code you don't really care about but are dependent on.

Simulating Exceptions

Another cool Typemock thing you can do is force existing code to throw an exception so you can test the robustness of your code.  What if I want to make sure my new code works OK if the mail relay is down on that legacy, sealed EmailService:

Isolate.WhenCalled(() => emailService.SendContactInfoToSales(contact)).WillThrow(new SmtpException());

You can do the same thing in Rhino Mocks.  Again, just different syntax:

emailService.Expect(x => x.SendContactInfoToSales(contact)).Throw(new SmtpException());

I think you would still need to have a mock on an IEmailService to do this with Rhino Mocks.  The Typemock advantage is that it can work around that sealed class.

Assert Syntax

Simple verifications

The interaction testing assert syntax for Rhino Mocks is:

// Assert
emailService.AssertWasCalled(x => x.SendContactInfoToSales(null), opt => opt.IgnoreArguments());

And for Typemock:

// Assert
Isolate.Verify.WasCalledWithAnyArguments(() => emailService.SendContactInfoToSales(null));

This is just to test that the code got to that line/made that call internally.  If you want to verify it got there and arrived with your expected arguments with Rhino Mocks:

// Assert
emailService.AssertWasCalled(x => x.SendContactInfoToSales(expectedContact);

And with Typemock:

// Assert
Isolate.Verify.WasCalled(() => emailService.SendContactInfoToSales(expectedContact));

So again, both frameworks can get you either assert type, just with different syntax.

Wrap up

The promise of Typemock Isolator is less time refactoring code that isn't on your roadmap and less setup to get to your system under test.  I've focused here mostly on the arrange syntax for that reason. 

Rhino Mocks can do most of the stuff Typemock can, except for the private, sealed, and static testing.  Some would argue that you shouldn't test that code or if you need to make it testable, you should refactor it anyway.

Maybe.  But it's also pretty appealing to keep your coding and tests focused on your project mandate, too.

Tags: ,
Categories: Technical


kick it on DotNetKicks.com shout it on DotNetShoutOut

Image Details