Wednesday, January 30, 2013

Learning JustMock for Working with Nasty Dependencies

Update: I totally forgot to give mad props to colleague and good pal Phil Japikse for walking me through a couple things over IM in the course if noodling all this out.

I’ve given my Unit Testing 101 talk ten or 20 times over the last four or five years and I love it. I enjoy getting folks introduced to unit testing without having to deal with dogma issues around Test Driven Development, Test Occasionally Development, etc.

Part of the talk hits up working with mocking in order to get past a dependency on external providers. The example I use is a security provider used to check whether or not the current user’s authorized to update info for an employee.

In the past I’ve used Rhino.Mocks to work through this. I’ve used Rhino in a few projects over the years and it’s been a great tool for me.

Being the rather dense guy I am, I forgot that the awesome company I work for has its own mocking tool: JustMock. I figured it made sense to alter my tests to work with JustMock, if for no other reason than I could speak halfway intelligently to questions on it from other folks I interact with in the community.

One of the things I was most interested in was dealing with badly handled dependencies in code. The example I used previously had a nice constructor-injected interface-based security provider, so it was easy and clean to handle with Rhino. Here’s how it looks:

public class EmployeeUpdater
{
    private readonly IUpdateEmployeePermissible _updateEmployeeSecurityProvider;
 
    public EmployeeUpdater(
        IUpdateEmployeePermissible updateEmployeeSecurityProvider)
    {
        _updateEmployeeSecurityProvider = updateEmployeeSecurityProvider;
    }
 
    public Employee UpdateEmployeeRate(Employee targetEmployee, float newRate)
    {
        Employee updatedEmployee;
        if (_updateEmployeeSecurityProvider.
            CanUpdateEmployeeRate(targetEmployee.EmployeeId))
        //if (true)
        {
            updatedEmployee = new Employee(
                targetEmployee.EmployeeId, 
                targetEmployee.FirstName,
                targetEmployee.LastName,
                targetEmployee.Address, newRate);
        }
        else
        {
            throw new SecurityException(
                "Invoking user doesn't have permissions to update target target employee. " +
                                        targetEmployee);
        }
        return updatedEmployee;
    }
}

A test using Rhino, complete with interaction verification, is straightforward:

[Test]
public void Verify_security_provider_is_called()
{
    int userId = 1;
    int oldRate = 5;
    int newRate = 10;
 
    var mockProvider = MockRepository.GenerateMock<IUpdateEmployeePermissible>();
    mockProvider.Expect(x => x.CanUpdateEmployeeRate(userId)).Return(true);
 
    Employee current = new Employee(userId, "Jim", "Holmes", "Doghouse", oldRate);
    EmployeeUpdater updater = new EmployeeUpdater(mockProvider);
 
    Employee updated = updater.UpdateEmployeeRate(current, newRate);
 
    mockProvider.VerifyAllExpectations();
}

I took and muddied up the EmployeeUpdater a bit to mimic code we’ve either written ourselves or have seen: “new”ing up objects instead of injecting them, and using calls to static methods or classes. These situations make it tough to mock things out and will force you to move to a commercial mocking tool like TypeMock or JustMock. [1] (JustMock has an extremely powerful free version, but mocking concrete classes, “future mocks” of items “new”ed up instead of injected, or static requires the commercial version.)

Here’s my uglified EmployeeUpdater class. I simply created two different methods, one which newed up the security provider in it, another which hit the provider via a static call.

public class EmployeeUpdaterLegacyStyle
{
    public Employee UpdateEmployeeRate_ProviderNewedUpHere(Employee targetEmployee, float newRate)
    {
        UpdateEmployeeSecurityProvider _updateEmployeeSecurityProvider =
            new UpdateEmployeeSecurityProvider();
 
        Employee updatedEmployee;
        if (_updateEmployeeSecurityProvider.
        CanUpdateEmployeeRate(targetEmployee.EmployeeId))
        //if (true)
        {
            updatedEmployee = new Employee(targetEmployee.EmployeeId,
                targetEmployee.FirstName,
                targetEmployee.LastName,
                targetEmployee.Address, newRate);
        }
        else
        {
            throw new SecurityException(
                                        "Invoking user doesn't have permissions to update target target employee. " +
                                        targetEmployee);
        }
        return updatedEmployee;
    }
 
    public Employee UpdateEmployeeRate_ProviderIsStaticHere(Employee targetEmployee, float newRate)
    {
        Employee updatedEmployee;
        if (UpdateEmployeeSecurityProvider_Static.CanUpdateEmployeeRate(targetEmployee.EmployeeId))
        //if (true)
        {
            updatedEmployee = new Employee(targetEmployee.EmployeeId,
                targetEmployee.FirstName,
                targetEmployee.LastName,
                targetEmployee.Address, newRate);
        }
        else
        {
            throw new SecurityException(
                                 "Invoking user doesn't have permissions to update target target employee. " +
                                        targetEmployee);
        }
        return updatedEmployee;
    }
}

JustMock handles both quite nicely. First, working with “future” mocking to handle the variant that instantiates the object in the method. Note I’m working with a concrete class. No interfaces, no virtual, just a straight concrete class that’s instantiated right in my method above. The final mockedProvider.Assert() validates the security provider’s method was indeed called by the updater. (Comment out the //if(true) portion in the updater to see that test fail!)

public void Mocking_provider_newed_in_method()
{
    int userId = 1;
    int oldRate = 5;
    int newRate = 10;
 
    var mockedProvider =
        Mock.Create<UpdateEmployeeSecurityProvider>();
    //Standard syntax for mocking
    //Mock.Arrange(() => 
    //    mockedProvider.CanUpdateEmployeeRate(userId))
    //        .IgnoreInstance()
    //        .Returns(true)
    //        .Occurs(1);
 
    //using the fluent interface from JustMock.Helpers 
    mockedProvider.Arrange(x => x.CanUpdateEmployeeRate(userId))
                  .IgnoreInstance()
                  .Returns(true)
                  .Occurs(1);
 
    Employee current =
        new Employee(userId, "Jim", "Holmes", "Doghouse", oldRate);
    EmployeeUpdaterLegacyStyle legacyUpdater =
        new EmployeeUpdaterLegacyStyle();
    
    Employee updated = 
        legacyUpdater.UpdateEmployeeRate_ProviderNewedUpHere(current, newRate);
 
    Assert.AreEqual(updated.HourlyRate, newRate);
    //Standard assert
    Mock.Assert(mockedProvider);
    //Fluent from Helpers
    mockedProvider.Assert();
}

Here’s a test handling the static call variant above:

[Test]
public void Mocking_provider_called_statically()
{
    int userId = 1;
    int oldRate = 5;
    int newRate = 10;
 
    Mock.SetupStatic(typeof(UpdateEmployeeSecurityProvider_Static),
        StaticConstructor.Mocked);
 
    bool called = false;
    Mock.Arrange(() => 
        UpdateEmployeeSecurityProvider_Static.CanUpdateEmployeeRate(userId))
        .Returns(true)
        .Occurs(1);
 
    Employee current =
        new Employee(userId, "Jim", "Holmes", "Doghouse", oldRate);
    EmployeeUpdaterLegacyStyle legacyUpdater =
        new EmployeeUpdaterLegacyStyle();
 
    Employee updated = 
        legacyUpdater.UpdateEmployeeRate_ProviderIsStaticHere(current, newRate);
 
    Assert.AreEqual(updated.HourlyRate, newRate);
    Mock.Assert(() => 
        UpdateEmployeeSecurityProvider_Static.CanUpdateEmployeeRate(userId),
        Occurs.Exactly(1));
}

I’m sure there are better ways to leverage JustMock, and I’m sure there are cleaner ways to write the test. This exercise was more about me learning what capabilities JustMock has so I could keep it somewhat clear in my own head.

I’d love to hear feedback from folks who’ve worked with both mocking tools! Have you worked with Rhino.Mocks and JustMock? Have any thoughts?

[1]Perhaps Rhino.Mocks now handles these situations. I fully admit I haven’t kept up with it…

No comments:

Post a Comment