Web API - owin 中的 HttpContext.Current 问题,用于使用 moq 进行集成测试

Posted

技术标签:

【中文标题】Web API - owin 中的 HttpContext.Current 问题,用于使用 moq 进行集成测试【英文标题】:Web API - Issues with HttpContext.Current in owin for integration testing using moq 【发布时间】:2019-08-12 16:03:33 【问题描述】:

我正在构建一个将托管在 IIS 环境中的 Web API 应用程序。为了对我的服务进行端到端集成测试(无模拟),我使用的是 OWIN。

问题在我的服务架构的深处,在存储库层,我使用HttpContext.Current 从标头(比如 UserId)中检索值。 See this answer

如果您查看上面的代码,我会在整个应用程序中使用GetUserInfo 方法来获取当前用户信息。另一种方法是在所有方法中将其作为参数传递(我个人不想这样做)。

我经历了这个很棒的answer,关于将IOwinContext 包含到存储库中。我已经尝试过了,它适用于自托管,但我的最终目标是在 IIS 上部署应用程序。

我的问题:

我的代码有什么方法可以同时处理 OWIN 自托管的用例以进行集成测试和 IIS 上的实际服务部署? 我的架构有问题吗?我根本不应该使用 OWIN,而是使用 POSTMAN 等其他工具进行测试。

如果需要,我可以发布一些代码。

编辑:

正如@Nkosi 所建议的,我可能必须模拟我的HeaderService 才能使用owin 执行集成测试。我不确定如何使用moq 模拟某种方法。这是我的代码。它的精简版是为了尽可能简单。

代码:

public class CreditController : ApiController

    private readonly ICreditService _creditService;

    public CreditController(ICreditService creditService)
    
        _creditService = creditService;
    

    public IHttpActionResult CreditSummary([FromUri]string requestId)
    
        var response = _creditService.GetCreditSummary(requestId);
        return Ok(response);
    


public class CreditService : ICreditService

    private readonly IHeaderService _headerService;
    private readonly ICreditRepository _creditRepository;

    public CreditService(ICreditRepository creditRepository, IHeaderService headerService)
    
        _headerService = headerService;
        _creditRepository = creditRepository;
    

    public CreditObj GetCreditSummary(string req)
    
        var userId = _headerService.GetHeaderFromHttpRequest();//Get User
        var response = _creditRepository.GetDataFromDatabase(req, userId);
        return response;
    


public interface IHeaderService

    string GetHeaderFromHttpRequest();


public class HeaderService : IHeaderService

    public string GetHeaderFromHttpRequest()
    
        return HttpContext.Current.Request.Headers["USERID"];
    

以下是我的集成测试代码:我使用 OWIN 进行自托管。所以我想调用控制器方法,但我的 GetHeaderFromHttpRequest 方法应该返回模拟响应。

[TestClass]
public class IntegrationTest

    private static HttpClient _client;
    private static IDisposable _webApp;

    [ClassInitialize]
    public static void Init(TestContext testContext)
    
        _webApp = WebApp.Start<Startup>(url: Url);
        _client = new HttpClient
        
            BaseAddress = new Uri(Url)
        ;
    

    [TestMethod]
    public void TestDashboard()
    
        var headerStub = new Mock<IHeaderService>();
        headerStub.Setup(s => s.GetHeaderFromHttpRequest())
            .Returns("MockUserId");

        var builder = new UriBuilder(Url + "api/Credit/CreditSummary");

        HttpResponseMessage responseMessage = _client.GetAsync(builder.ToString()).Result;
        Assert.IsNotNull(responseMessage);
    


public class Startup

    public void Configuration(IAppBuilder app)
    
        var config = new HttpConfiguration();
        WebApiConfig.Register(config); //This method having all routing/dependancy configuration
        app.UseWebApi(config);
    

问题:

当我调试这个测试用例时,我如何确保_headerService.GetHeaderFromHttpRequest() 返回模拟响应。到目前为止,我不知道如何将我的模拟服务注入到实际的控制器方法调用中。

有什么建议吗?

【问题讨论】:

您仍然可以使用模拟进行端到端测试。如果在这种情况下,您实际上并没有在 IIS 上运行,(这是HttpContext.Current 工作所需要的)那么您仍然需要模拟抽象服务以避免静态耦合. 我不确定我是否理解正确。你是说我应该在集成测试中模拟HttpContext.Current 和/或HeaderService(使用HttpContext 对象的服务)?不确定,在进行集成测试时,这是否是一种模拟任何东西的好方法。 显示的Startup是用于测试的吗?您可以注册一个知道IHeaderService 的依赖解析器,以便在注入模拟时返回它。 【参考方案1】:

根据@Nkosi 的建议,我能够模拟HeaderService 进行集成测试。

代码如下:

var container = new UnityContainer();

var mock = new Mock<IHeaderService>();
mock.Setup(x => x.GetHeaderFromHttpRequest()).Returns("MockId");
container.RegisterInstance(mock.Object);

【讨论】:

【参考方案2】:

我关注了这个话题,并在我的旧项目中使用了HttpContextBase

Moq: unit testing a method relying on HttpContext

HttpContextWrapper是HttpContext类的封装,可以这样构造一个HttpContextWrapper:

var wrapper = new HttpContextWrapper(HttpContext.Current);

您可以模拟 HttpContextBase 并使用 Moq 设置您对它的期望

var mockContext = new Mock<HttpContextBase>();

【讨论】:

以上是关于Web API - owin 中的 HttpContext.Current 问题,用于使用 moq 进行集成测试的主要内容,如果未能解决你的问题,请参考以下文章

身份验证/授权 MVC 5 和 Web API - Katana/Owin

使用 OData 响应 Owin Self-Host 忽略 Web Api 中的 Null 属性/值

Asp.Net Web API 2第十课——使用OWIN自承载Web API

无法使用 Owin 退出 Web Api

JSON Web Token in ASP.NET Web API 2 using Owin

SimpleInjector不起作用--OWIN上的Web API