2

I am building a Web API application which will be hosted in an IIS environment. In order to perform end to end integration testing of my service(no mocking), I am using OWIN.

The problem is deep down in my service architecture, at the repository layer I am making use of HttpContext.Current to retrieve values from the header(say UserId). See this answer

If you look into the above code, I am making use GetUserInfo method throughout my application to fetch current user information. Another way to do is pass it as a parameter in all method(which I don't personally want to do).

I went through this great answer about including IOwinContext into the repository. I have tried it and it worked for self-hosting, but my end goal is to deploy the application on IIS.

My Questions:

  • Is there any way my code can handle both the use cases of OWIN self-hosting for integration testing & actual service deployment on IIS?
  • Is there any issue with my architecture? Something like I shouldn't be using OWIN at all, and use other tools like POSTMAN for testing.

I can post some code if it's required.

Edit:

As suggested by @Nkosi I might have to mock my HeaderService in order to perform integration testing with owin. I am not sure how can I mock one certain method using moq. Here is my code. Its strip down version in order to make as simple as possible.

Code:

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"];
    }
}

Below is my code for integration testing: I am using OWIN for self-host. So i want to call the controller method but my GetHeaderFromHttpRequest method should return mock response.

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

Problem:

  • When I debug this test case, how do I make sure that _headerService.GetHeaderFromHttpRequest() return mock response. As of now I dont know how can i inject my mocking service to actual controller method call.

Any advise?

Shaggy
  • 5,422
  • 28
  • 98
  • 163
  • You can still do end to end testing with a mock. If in this case you are not actually running on IIS, (*which is what you would need in order for `HttpContext.Current` to work*) Then you would still need to mock the abstracted service to avoid that static coupling. – Nkosi Mar 22 '19 at 09:48
  • I am not sure if I understood you correctly. Are you saying that I should mock `HttpContext.Current` and/or `HeaderService` (service which uses HttpContext object) in my integration test? Not sure, if it's a good approach to mock anything when doing integration testing. – Shaggy Mar 22 '19 at 16:37
  • Is the shown `Startup` the one used for the test? You can register a dependency resolver that is aware of the `IHeaderService` to return the mock when it is to be injected. – Nkosi Mar 23 '19 at 01:14

2 Answers2

1

Based on @Nkosi's suggestion I was able to mock HeaderService for my integration testing.

Here is the code:

var container = new UnityContainer();

var mock = new Mock<IHeaderService>();
mock.Setup(x => x.GetHeaderFromHttpRequest()).Returns("MockId");
container.RegisterInstance(mock.Object);
Shaggy
  • 5,422
  • 28
  • 98
  • 163
0

I followed this topic and use HttpContextBase in my old project.

Moq: unit testing a method relying on HttpContext

HttpContextWrapper is a wrapper for the HttpContext class, can construct an HttpContextWrapper like this:

var wrapper = new HttpContextWrapper(HttpContext.Current);

You can mock an HttpContextBase and set up your expectations on it using Moq

var mockContext = new Mock<HttpContextBase>();
Hien Nguyen
  • 24,551
  • 7
  • 52
  • 62