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 开发者_StackOverflow中文版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
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.)
精彩评论