Unit Test Controller mocking ISession

Viewed 1221

I want to Unit Test my Controller, but I'm having issues reading values from HttpContext.Session.
I want to mock this piece from my Controller: HttpContext.Session.Get<int>(Foo)

With Mock HttpContext for unit testing a .NET core MVC controller? and How to mock Session Object in asp net core I was able to come to the following solution:

My Test:

public void GetFoos_AllGood_ReturnList()
{
  //Arrange
  Mock<ISession> sessionMock = new Mock<ISession>();
  var fooSessionValue = new byte[0];

  Web.Controllers.FooController fooController = new Web.Controllers.FooController();
  fooController.ControllerContext.HttpContext = new DefaultHttpContext();
  fooController.ControllerContext.HttpContext.Request.Headers["Foo"] = 0;

  Mock<IServiceCollection> mock = new Mock<IServiceCollection>();
  mock.Object.AddSession(); // Tried this, but failed

  //Setup
  sessionMock.Setup(_ => _.Set("Foo", It.IsAny<byte[]>())).Callback<string, byte[]>((k, v) => fooSessionValue = v);
  sessionMock.Setup(_ => _.TryGetValue("Foo", out fooSessionValue)).Returns(true);
  mockWebDataManager.Setup(b => b.GetFoos(It.IsAny<FooArgs>())).Returns(new FooResult() { Foos = new List<Foo>() });

  //Act
  var result = fooController.GetFoos() as JsonResult;

  //Assert
  Assert.NotNull(result);
  Assert.Equal(200, result.StatusCode);
}

My Controller:

internal virtual DataArgs CreateArgs()
{
  return new FooArgs
  {
     HttpContext.Session.Get<int>(Foo) // I want to Mock this value    
  };
}

[HttpGet]
public IActionResult GetFoos()
{
  FooArgs args = CreateArgs();
  ...
}
2 Answers

If anyone faces the same issue one day, here you go:

public void GetFoos_AllGood_ReturnList()
{
  //Arrange
  Mock<ISession> sessionMock = new Mock<ISession>();

  Web.Controllers.FooController fooController = new Web.Controllers.FooController();
  fooController.ControllerContext.HttpContext = new DefaultHttpContext();
  fooController.ControllerContext.HttpContext.Request.Headers["Foo"] = 0; 
  fooController.ControllerContext.HttpContext.Session = sessionMock.Object;

  //Act
  var result = fooController.GetFoos() as JsonResult;

  //Assert
  Assert.NotNull(result);
}

Thanks Hypernate for the answer but In my case I had to deal with GetInt32 and SetInt32 extension methods in the unit test. As per the source code below is the implementation

public static void SetInt32(this ISession session, string key, int value)
        {
            var bytes = new byte[]
            {
                (byte)(value >> 24),
                (byte)(0xFF & (value >> 16)),
                (byte)(0xFF & (value >> 8)),
                (byte)(0xFF & value)
            };
            session.Set(key, bytes);
        }

public static int? GetInt32(this ISession session, string key)
        {
            var data = session.Get(key);
            if (data == null || data.Length < 4)
            {
                return null;
            }
            return data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
        }

so following what's mentioned by as answer I had to modify little bit as below to handle it.

 Mock<ISession> sessionMock = new Mock<ISession>();
        var key = "FY";
        int fy = 2020;
        var value =  new byte[]
        {
            (byte)(fy >> 24),
            (byte)(0xFF & (fy >> 16)),
            (byte)(0xFF & (fy >> 8)),
            (byte)(0xFF & fy)
        };

  sessionMock.Setup(_ => _.TryGetValue(key, out value)).Returns(true);

I couldn't find this anywhere so sharing here in case it is helpful for someone who are having same issue.

Related