【问题标题】:Trying to test two controller actions that share Session data. MVC尝试测试共享会话数据的两个控制器操作。 MVC
【发布时间】:2016-04-24 05:25:36
【问题描述】:

我正在尝试编写一个检查两个控制器操作的单元测试。这些控制器动作依赖于 Session 变量。到目前为止,我有这个:

单元测试:

[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 像这样为控制器设置会话:

//...
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 设置 Session 变量:

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);
    //...
}

在运行时,代码有效。通过单元测试,SubmissionIndex 将 Session["SelectedSubmissions"] 视为 null。

我是否设置了假控制器的会话错误?测试时如何使用 Session?

更新:我经常从重定向调用 SubmissionIndex 操作:
Session["SelectedSubmissions"] = model.Submissions.Where(s => s.Selected).ToList(); return RedirectToAction("SubmissionIndex", "Project", routeValues);

【问题讨论】:

  • 当您可以将 List 作为参数传递给 SubmissionIndex 方法时,我仍然不明白为什么要使用会话...您是否在其他地方使用会话进行测试?
  • 是的,我是。我试图使示例尽可能简单且易于阅读。但是两个 Session 值(如上所示)都需要在其他地方访问。

标签: asp.net-mvc unit-testing


【解决方案1】:

您是否尝试过更直接地模拟它:

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

或者您甚至可以根据通用输入返回

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

示例

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();
}

【讨论】:

  • 我正在尝试理解您的建议。我可能需要获取多个会话变量。 Session["SelectedSubmissions"]Session["reportData"]
  • 然后分别模拟它们中的每一个,这样您就可以确保准确地返回什么。因此,我会做两个设置; .Setup(x =&gt; x["SelectedSubmissions"]).Setup(x =&gt; x["reportData"])。在模拟属性时,我认为您必须非常具体,我有一种轻微的感觉,使用方括号访问属性实际上会调用未模拟的方法。
  • 另外,您是否考虑过使用 [TestSetup] 来配置模拟并公开控制器?
  • 如果我想测试控制器操作是否正确操纵了 Session 变量怎么办?可以这样做吗?或者这就是你的建议?
  • 我会读到这个:stackoverflow.com/a/16818328/3002953。我建议不要嘲笑你要操纵的东西,例如测试。从你的例子我知道这有点棘手,也许重新考虑你的控制器方法和你的测试?
猜你喜欢
  • 1970-01-01
  • 2012-01-10
  • 2011-01-08
  • 1970-01-01
  • 2014-08-11
  • 1970-01-01
  • 1970-01-01
  • 2010-09-15
  • 2013-01-28
相关资源
最近更新 更多