views:

123

answers:

1

Hello,

I trying to test an AccountController that uses DotNetOpenAuth but I am running into a problem. I want to test the Logon Actionresult to see that it is returning the correct views. The test fails because realm(I think) has a contract that requires the HttpContext.Current not to be null. I think I have to mock the request somehow but I am not sure how I should do this.

This is the ActionResult code. It's taken directly from a DotNetOpenAuth example.

[AcceptVerbs(HttpVerbs.Post), ValidateAntiForgeryToken]
public ActionResult LogOn(string openid_identifier, 
                          bool rememberMe, 
                          string returnUrl)
{
    Identifier userSuppliedIdentifier;
    if (Identifier.TryParse(openid_identifier, out userSuppliedIdentifier))
    {
        try
        {
            var request = this.RelyingParty
                              .CreateRequest(openid_identifier,
                                             Realm.AutoDetect, 
                                             Url.ActionFull("LogOnReturnTo"));

            if (!string.IsNullOrEmpty(returnUrl))
            {
                request.SetUntrustedCallbackArgument("returnUrl", returnUrl);
            }
            return request.RedirectingResponse.AsActionResult();
        }
        catch (ProtocolException ex)
        {
            ModelState.AddModelError("OpenID", ex.Message);
        }
    }
    else
    {
        ModelState.AddModelError("openid_identifier", 
                                 "This doesn't look like a valid OpenID.");
    }
    return RedirectToAction("LogOn", "Account");
}

Thanks in advance,

Pickels

+2  A: 

If one of the Controller's dependencies requires that HttpContext.Current is available, you can't really mock it out directly, but you can wrap that dependency in a testable abstraction itself.

If we assume that Realm is the culprit, you must first extract an interface from it:

public interface IRealm
{
    // I don't know what the real AutoDetect property returns,
    // so I just assume bool
    bool AutoDetect { get; }
}

You would obviously need a real implementation of IRealm:

public class RealmAdapter : IRealm
{
    bool AutoDetect { get { return Realm.AutoDetect; } }
}

You must inject the abstract IRealm into the controller, for instance by using Constructor Injection

public class MyController
{
    private readonly IRealm realm;

    public MyController(IRealm realm)
    {
        if( realm == null)
        {
            throw new ArgumentNullException("realm");
        }

        this.realm = realm;
    }
}

You can now change your implementation of the LogOn method to use this.realm instead of relying directly on the Realm class.

A unit test would now be able to supply a mock IRealm instance to the controller:

var realmMock = new Mock<IRealm>();
var sut = new MyController(realmMock.Object);

(This example uses Moq.)

Mark Seemann