2

I have a method:

public DataSet someMethod()
{
    List a = someObj.getList(name, integerId);
}

Now the integerId is obtained through the HttpContext.Current.Session variable. I have written a unit test for the method. But since, the test runs outside of the web process, HttpContext.Current.Session returns null and the test fails.

Is there any workaround for this?

Anoop R Desai
  • 712
  • 5
  • 18
  • 1
    Mocking HttpContext is difficult in classic ASP.NET. I suggest you wrap your references to HttpContext.Session in your own mockable class. – Joe Apr 28 '16 at 06:48
  • Data acess layer should not depends on HttpContext object. – izsl Apr 28 '16 at 14:14
  • Yes, ideally that should be the case. However, in order to follow that, a large amount of code in my project would have to be re factored. – Anoop R Desai Apr 29 '16 at 11:06

3 Answers3

1

First you'll have to initialize HttpContext.Current:

HttpContext.Current = new HttpContext(new HttpRequest("", "http://blabla.com", "") {},
                                      new HttpResponse(new StringWriter()));

Then you'll have to set the session:(Necroskillz has explained the way to do this in his blog)

public static void SetFakeSession(this HttpContext httpContext)
{
    var sessionContainer = new HttpSessionStateContainer("id", 
                                             new SessionStateItemCollection(),
                                             new HttpStaticObjectsCollection(), 10, true,
                                             HttpCookieMode.AutoDetect,
                                             SessionStateMode.InProc, false);

    httpContext.Items["AspSession"] = typeof(HttpSessionState).GetConstructor(
                                             BindingFlags.NonPublic | BindingFlags.Instance,
                                             null, CallingConventions.Standard,
                                             new[] { typeof(HttpSessionStateContainer) },
                                             null)
                                        .Invoke(new object[] { sessionContainer });
}

The following snippet shows how it works:

[TestMethod]
public void TestMethod1()
{
    HttpContext.Current = new HttpContext(new HttpRequest("", "http://blabla.com", "") {},
                                          new HttpResponse(new StringWriter()));

    HttpContext.Current.SetFakeSession();

    HttpContext.Current.Session["foo"] = 1;

    Assert.AreEqual(1, HttpContext.Current.Session["foo"]);
}
Community
  • 1
  • 1
Old Fox
  • 8,629
  • 4
  • 34
  • 52
1

I guess the lazy answer to this question would be: learn to use dependency injection, but I'll go ahead and provide some pointers.

It is unlikely the class needs everything in HttpContext. You don't specify how you compute your integerId, but let's say it's a hash of the current SessionState's SessionId. All your class actually need is some way to get that particular SessionId; that doesn't need to be an entire HttpContext.

interface ICurrentSessionIdProvider
{
     string SessionId { get; }
}

And now your class has:

// Pull this from a constructor parameter so you can provide any implementation you want
private readonly ICurrentSessionIdProvider _sessionIdProvider;

public DataSet someMethod()
{
     int integerId = _sessionIdProvider.SessionId.GetHashCode();
     List a = someObj.getList(name, integerId);
}

Now in your unit test it becomes trivial to mock this dependency. Tools like Moq and AutoFixture will even do it for you and now your life is easy and happy etc.

Of course in the real application you want to use an implementation based on HttpContext:

class HttpContextCurrentSessionIdProvider : ICurrentSessionIdProvider   
{
     // Pull this from a constructor parameter or however you see fit.
     private readonly HttpContext _httpContext;

     public SessionId => _httpContext.Current.Session.SessionId;
}  
Community
  • 1
  • 1
Asik
  • 21,506
  • 6
  • 72
  • 131
0

You'll need to inject a fake HttpContext for your test somehow - ideally as HttpContextBase, which is a mockable but otherwise identical API.

You can wrap HttpContext in an HttpContextWrapper to get an HttpContextBase.

Have a read up on the various techniques for Inversion of Control, and find one that works for you.

yaakov
  • 5,552
  • 35
  • 48