Setting HttpContext.Current.Session in a unit test

2019-01-01 08:16发布

I have a web service I am trying to unit test. In the service it pulls several values from the HttpContext like so:

 m_password = (string)HttpContext.Current.Session["CustomerId"];
 m_userID = (string)HttpContext.Current.Session["CustomerUrl"];

in the unit test I am creating the context using a simple worker request, like so:

SimpleWorkerRequest request = new SimpleWorkerRequest("", "", "", null, new StringWriter());
HttpContext context = new HttpContext(request);
HttpContext.Current = context;

However, whenever I try to set the values of HttpContext.Current.Session

HttpContext.Current.Session["CustomerId"] = "customer1";
HttpContext.Current.Session["CustomerUrl"] = "customer1Url";

I get null reference exception that says HttpContext.Current.Session is null.

Is there any way to initialize the current session within the unit test?

13条回答
荒废的爱情
2楼-- · 2019-01-01 08:35

I found the following simple solution for specifying a user in the HttpContext: https://forums.asp.net/post/5828182.aspx

查看更多
弹指情弦暗扣
3楼-- · 2019-01-01 08:41

If you're using the MVC framework, this should work. I used Milox's FakeHttpContext and added a few additional lines of code. The idea came from this post:

http://codepaste.net/p269t8

This seems to work in MVC 5. I haven't tried this in earlier versions of MVC.

HttpContext.Current = MockHttpContext.FakeHttpContext();

var wrapper = new HttpContextWrapper(HttpContext.Current);

MyController controller = new MyController();
controller.ControllerContext = new ControllerContext(wrapper, new RouteData(), controller);

string result = controller.MyMethod();
查看更多
高级女魔头
4楼-- · 2019-01-01 08:42

I worte something about this a while ago.

Unit Testing HttpContext.Current.Session in MVC3 .NET

Hope it helps.

[TestInitialize]
public void TestSetup()
{
    // We need to setup the Current HTTP Context as follows:            

    // Step 1: Setup the HTTP Request
    var httpRequest = new HttpRequest("", "http://localhost/", "");

    // Step 2: Setup the HTTP Response
    var httpResponce = new HttpResponse(new StringWriter());

    // Step 3: Setup the Http Context
    var httpContext = new HttpContext(httpRequest, httpResponce);
    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 });

    // Step 4: Assign the Context
    HttpContext.Current = httpContext;
}

[TestMethod]
public void BasicTest_Push_Item_Into_Session()
{
    // Arrange
    var itemValue = "RandomItemValue";
    var itemKey = "RandomItemKey";

    // Act
    HttpContext.Current.Session.Add(itemKey, itemValue);

    // Assert
    Assert.AreEqual(HttpContext.Current.Session[itemKey], itemValue);
}
查看更多
何处买醉
5楼-- · 2019-01-01 08:43

I was looking for something a little less invasive than the options mentioned above. In the end I came up with a cheesy solution, but it might get some folks moving a little faster.

First I created a TestSession class:

class TestSession : ISession
{

    public TestSession()
    {
        Values = new Dictionary<string, byte[]>();
    }

    public string Id
    {
        get
        {
            return "session_id";
        }
    }

    public bool IsAvailable
    {
        get
        {
            return true;
        }
    }

    public IEnumerable<string> Keys
    {
        get { return Values.Keys; }
    }

    public Dictionary<string, byte[]> Values { get; set; }

    public void Clear()
    {
        Values.Clear();
    }

    public Task CommitAsync()
    {
        throw new NotImplementedException();
    }

    public Task LoadAsync()
    {
        throw new NotImplementedException();
    }

    public void Remove(string key)
    {
        Values.Remove(key);
    }

    public void Set(string key, byte[] value)
    {
        if (Values.ContainsKey(key))
        {
            Remove(key);
        }
        Values.Add(key, value);
    }

    public bool TryGetValue(string key, out byte[] value)
    {
        if (Values.ContainsKey(key))
        {
            value = Values[key];
            return true;
        }
        value = new byte[0];
        return false;
    }
}

Then I added an optional parameter to my controller's constructor. If the parameter is present, use it for session manipulation. Otherwise, use the HttpContext.Session:

class MyController
{

    private readonly ISession _session;

    public MyController(ISession session = null)
    {
        _session = session;
    }


    public IActionResult Action1()
    {
        Session().SetString("Key", "Value");
        View();
    }

    public IActionResult Action2()
    {
        ViewBag.Key = Session().GetString("Key");
        View();
    }

    private ISession Session()
    {
        return _session ?? HttpContext.Session;
    }
}

Now I can inject my TestSession into the controller:

class MyControllerTest
{

    private readonly MyController _controller;

    public MyControllerTest()
    {
        var testSession = new TestSession();
        var _controller = new MyController(testSession);
    }
}
查看更多
ら面具成の殇う
6楼-- · 2019-01-01 08:44

The answer that worked with me is what @Anthony had written, but you have to add another line which is

    request.SetupGet(req => req.Headers).Returns(new NameValueCollection());

so you can use this:

HttpContextFactory.Current.Request.Headers.Add(key, value);
查看更多
公子世无双
7楼-- · 2019-01-01 08:45

You can try FakeHttpContext:

using (new FakeHttpContext())
{
   HttpContext.Current.Session["CustomerId"] = "customer1";       
}
查看更多
登录 后发表回答