0

I'm trying to write a Unit test that checks two controller actions. These controller actions rely on Session variables. So far I have this:

Unit Test:

[TestMethod]
public void TableOfContentReportTest()
{
    // Arrange
    var fakeDb = TestFakes.SetupFakeDbContext();
    var controller = TestFakes.ProjectController(fakeDb);

    // Act
    var selectedSubs = AutoMapper.Mapper.Map<ProjectSubmissionViewModel>(fakeDb.ProjectSubmission.FirstOrDefault());
    selectedSubs.Selected = true;
    controller.Session["SelectedSubmissions"] = new List<ProjectSubmissionViewModel> {selectedSubs};

    var result = controller.SubmissionIndex("ProjectTitle", true,1, 10,"","","","","",
        StaticStrings.Report_TableOfContents) as ViewResult;

    // Assert
    Assert.IsNotNull(result);

    var testSession = controller.processReport();
}

TestFakes.ProjectController sets up the session for the controller like this:

//...
var session = new Mock<HttpSessionStateBase>();
var context = new Mock<HttpContextBase>(MockBehavior.Strict);
context.SetupGet(x => x.Session).Returns(session.Object);

var rc = new RequestContext(context.Object, new RouteData());
var controller = new ProjectController(fakeDb);
controller.ControllerContext = new ControllerContext(rc, controller);
//...

SubmissionIndex sets the Session variable:

public virtual ActionResult SubmissionIndex(
    string sortBy = "ProjectTitle", 
    bool ascending = true,
    int page = 1, 
    int pageSize = 10,
    string projectId = "",
    string submissiontitle = "",
    string firstname = "",
    string lastname = "",
    string email = "",
    string showreport = "")
{
    var selectedSubmissions = Session["SelectedSubmissions"] as ICollection<ProjectSubmissionViewModel>;
    //... Uses selectedSubmissions to build bookResources and chapters
    Session["reportData"] = viewModel.GetContentsReport(bookResources, chapters);
    //...
}

At runtime, the code works. With the unit test, SubmissionIndex sees Session["SelectedSubmissions"] as null.

Am I setting up the fake controller's session wrong? How can I work with the Session while testing?

Update: I often call the SubmissionIndex action from a Redirect:
Session["SelectedSubmissions"] = model.Submissions.Where(s => s.Selected).ToList(); return RedirectToAction("SubmissionIndex", "Project", routeValues);

M Kenyon II
  • 4,136
  • 4
  • 46
  • 94
  • i still don't get why you are using a session when you can just pass the List as a parameter to the SubmissionIndex method... are you using the session with your tests elsewhere? – ymz Jan 18 '16 at 22:17
  • Yes I am. I tried to get the example as simple as possible and easy to read. But both Session values (as seen above) need to be accessible elsewhere. – M Kenyon II Jan 19 '16 at 13:30

1 Answers1

0

Have you tried mocking it a bit more directly:

var session = new Mock<HttpSessionStateBase>();
var myCollection = new ICollection<ProjectSubmissionViewModel> { object1, object2... etc };
session.Setup(x => x["SelectedSubmissions"]).Returns(myCollection);

Or you could even return based on a generic input

session.Setup(x => x[It.IsAny<string>()]).Returns(myCollection);

Example

private ProjectController controller;

[TestSetup]
public void Setup()
{
    var dbMock = new Mock<db>();

    //Set up properties etc 
    var context = new Mock<HttpContextBase>(MockBehavior.Strict);
    context.SetupGet(x => x.Session["SelectedSubmissions"]).Returns(object1);
    context.SetupGet(x => x.Session["reportStuff"]).Returns(object2);
    controller = new ProjectController(dbMock.Object);
}

[TestMethod]
public void TableOfContentReportTest()
{
    var result = controller.SubmissionIndex(
              "ProjectTitle",
              true,
              1, 10,"","","","","",
              StaticStrings.Report_TableOfContents) as ViewResult;

    // Assert
    Assert.IsNotNull(result);

    var testSession = controller.processReport();
}
Heberda
  • 830
  • 7
  • 29
  • I'm trying to understand your suggestion. I may have more than one session variable I need to get. `Session["SelectedSubmissions"]`, `Session["reportData"]`, etc. – M Kenyon II Jan 19 '16 at 20:28
  • Then mock each of them individually so you can ensure exactly what is coming back. I would therefore do two setups; `.Setup(x => x["SelectedSubmissions"])` and `.Setup(x => x["reportData"])`. When mocking properties I think you have to be quite specific, I have a slight feeling accessing the properties using square brackets will infact call an un-mocked method. – Heberda Jan 20 '16 at 15:54
  • Also, have you thought about using a [TestSetup] to configure the mocks and expose the controller? – Heberda Jan 20 '16 at 16:12
  • What if I want to test that the controller action manipulates the Session variable correctly? Can that be done? Or is that what you're suggesting? – M Kenyon II Jan 20 '16 at 18:58
  • I'd have a read of this: http://stackoverflow.com/a/16818328/3002953. I'd suggest not mocking something your going to manipulate e.g. Test. From your example I understand this is a bit tricky, maybe reconsider your controller methods and what your testing? – Heberda Jan 21 '16 at 16:06