【问题标题】:unit testing dotnetopenauth ctp单元测试 dotnetopenauth ctp
【发布时间】:2012-01-19 23:23:30
【问题描述】:

我正在使用 DotNetOpenAuth CTP 库实现一个 oauth 提供程序。所以我创建了一个 mvc3 应用程序,它有一个 OAuth 控制器,里面有 3 个方法,目的是授权第三方应用程序。控制器有一个 IOAuthService,它封装了库为完成某些任务必须执行的所有逻辑,但是,服务方法返回的 DotNetOpenOAuth 对象的构造函数受到保护。

我想测试我的 OAuthController 中方法的行为,为此,我试图模拟我的服务方法,但我无法做到这一点。我必须告诉 moq 库我期望服务方法返回什么类型的对象,并且由于我无法访问这些对象的构造函数,因此我无法对我的控制器方法执行测试。

控制器:

public class OAuthController : Controller
{
    private readonly IOAuthService _oAuthService;

    public OAuthController(IOAuthService oAuthService)
    {
        _oAuthService = oAuthService;
    }

    [Authorize, AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
    public ActionResult Authorize()
    {
        ClientApplication requestingClient;
        var request = _oAuthService.ReadAuthorizationRequest();
        if (request == null)
        {
            throw new HttpException((int)HttpStatusCode.BadRequest, "Missing authorization request.");
        }

        var response = _oAuthService.RequestClientAuthorization(GetIdentity().Name, out requestingClient, request);
        if (response != null)
        {
            return response.AsActionResult();
        }

        var model = new AuthorizeClientApplicationViewModel
        {
            ClientApplication = requestingClient.Name,
            Scope = request.Scope,
            AuthorizationRequest = request,
        };

        return View(model);
    }

    public virtual IIdentity GetIdentity()
    {
        return User.Identity;
    }
}

我想测试一下,每当第三方应用程序没有授权时,都会弹出一个视图,要求用户授权该应用程序。我需要嘲笑这个:

  • _oAuthService.RequestClientAuthorization

我的测试方法的设置将如下所示:

var oAuthService = new Mock<IOAuthService>();
oAuthService.Setup(a => a.RequestClientAuthorization(userName, out client, pendingRequest)).Returns(new OutgoingWebResponse()); // DotNetOpenAuth doesn't allow me to do the **new OutgoingWebResponse**

PD:对于这个问题,我只写了一个控制器方法,但有3个,它们的场景相似。

【问题讨论】:

    标签: c# asp.net-mvc dotnetopenauth


    【解决方案1】:

    一种可能性是编写一个包装器(与 ASP.NET MVC 抽象所有 HTTP 上下文特定内容的方式相同):

    public abstract class OutgoingWebResponseWrapperBase
    {
        protected OutgoingWebResponseWrapperBase() { }
    
        public abstract ActionResult AsActionResult();
    }
    

    然后有一个幼稚的实现:

    public class OutgoingWebResponseWrapper: OutgoingWebResponseWrapperBase
    {
        private readonly OutgoingWebResponse _response;
        public OutgoingWebResponseWrapper(OutgoingWebResponse response)
        {
            _response = response;
        }
    
        public override ActionResult AsActionResult()
        {
            return _response.AsActionResult();
        }
    }
    

    现在修改IOAuthService.RequestClientAuthorization 方法以返回OutgoingWebResponseWrapperBase 而不是OutgoingWebResponse

    就这样:

    public interface IOAuthService
    {
        ...
        OutgoingWebResponseWrapperBase RequestClientAuthorization(...);
    }
    

    显然,您的控制器代码将保持不变。只是现在您可以在单元测试中模拟RequestClientAuthorization 的返回类型,因为它是一个抽象类。您还可以模拟 AsActionResult 抽象方法调用以返回一些预期的模拟实例,并且您将在单元测试中断言您正在测试的控制器操作返回了此预期的操作结果。

    【讨论】:

      【解决方案2】:

      如果构造函数受到保护,则派生类型可以访问它。你能简单地使用 Moq 创建一个 OutgoingWebResponse 的模拟(内部将使 Moq 从它派生并调用我认为的受保护构造函数)并从你的模拟方法实现中返回它吗?

      类似这样的:

      System.Net.HttpWebResponse mockResponse; // get this from somewhere
      new Moq.Mock<DotNetOpenAuth.Messaging.OutgoingWebResponse>(mockResponse, 5);
      

      这应该让您模拟 OutgoingWebResponse。下一个问题是,你从哪里获得 yoru HttpWebResponse 实例,因为它也只有一个受保护的构造函数。您可以继续该链并模拟与 OutgoingWebResponse 相同的内容,然后看看您能走多远。

      【讨论】:

      • 您能否提供一个参考,举例说明如何实施该理论?
      • 不,我已经尝试过了,但是系统会抛出一个异常,告诉必须明确定义父构造函数。
      • 添加了一个例子。如果有 HttpWebResponse,则可以做到。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-07
      • 1970-01-01
      • 2012-02-04
      • 1970-01-01
      • 2019-06-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多