测试/模拟DotNetOpenAuth控制器

时间:2010-03-04 08:58:19

标签: asp.net-mvc mocking dotnetopenauth

我尝试测试使用DotNetOpenAuth的AccountController,但我遇到了问题。我想测试Logon Actionresult,看它是否正在返回正确的视图。测试失败,因为领域(我认为)有一个合同,要求HttpContext.Current不为null。我想我必须以某种方式嘲笑这个请求,但我不确定我该怎么做。

这是ActionResult代码。它直接来自DotNetOpenAuth示例。

[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");
}

提前致谢,

Pickels

1 个答案:

答案 0 :(得分:2)

如果Controller的某个依赖项要求HttpContext.Current可用,则无法直接将其模拟出来,但是您可以将该依赖项包装在可测试的抽象中。

如果我们假设Realm是罪魁祸首,您必须首先从中提取

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

你显然需要真正实现IRealm:

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

您必须将抽象的IRealm注入控制器,例如使用构造函数注入

public class MyController
{
    private readonly IRealm realm;

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

        this.realm = realm;
    }
}

您现在可以将LogOn方法的实现更改为使用this.realm,而不是直接依赖于Realm类。

单元测试现在可以向控制器提供模拟IRealm实例:

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

(此示例使用Moq。)