dotnet/systemweb-adapters

How to set up mocks/stubs for testing?

munichmule opened this issue · 3 comments

Hello,

Let's say I have some old method and xunit test for it:

int MyMethod() {
   HttpContext.Current.Response.Cookies.Add("foo", "bar");
   HttpContext.Current.Response.Write("whatever");
   return 123;
}

[Fact]
void MyTest() {
   // stub
   HttpContext.Current = new HttpContext(new HttpRequest("page.aspx", "http://localhost/", null), new HttpResponse(new StringWriter()));

   // test code
   var result = MyMethod();
   Assert.Equal(123, result);
}

What is needed to make the test work in netcore with adapter?
I can rewrite the test, but not the method under test (that's the reason for using the adapter).

The only way I've found so far is to run a full-blown inmemory test server, similar to this test in the repo.
But that's quite an overkill: I don't want to test ASP.NET features, I want to stub them.

Since you effectively are testing ASP.NET Features by writing directly to the HttpContext, it seems reasonable to host it in a test server (which you can abstract in a way to hide the complexity). There are behaviors that may now rely on middleware to be run in the pipeline for things to show up as you expect.

However, if that is not desirable, you have a few options:

  1. HttpContext.Current is backed by HttpContextAccessor.Current, which you can set. If you'd like to see HttpContext.Current settable, please file a separate issue for that so we can discuss it there.
  2. You can construct the context/request/response using the DefaultHttpContext and set the appropriate features for path,etc

or

  1. Investigate enabling those overloads for context/request/response. We take PRs :)

The bad thing about having a dependency on a real ASP.NET pipeline is not the need to run the host, but the need to actually mimic requests (for instance. HttpContext.Current.Request.Form needs post request to be made, otherwise it fails on attempt to read body content type etc).

Unfortunately the simple approach you suggest doesn´t work: using DefaultHttpContext was the first thing I tried.
I can inject some required http feature mocks into it via IHttpContext.Features.Set<T>, but not all of them are public (IHttpResponseEndFeature etc). It makes sense to have all these interfaces publicly available, so one could inject mocks for the code being executed outside of ASP.NET pipeline.

I haven't made those public as haven't seen a need. If it would help with testing, we can do that.