【问题标题】:Unit testing of controller ends in error控制器的单元测试以错误结束
【发布时间】:2011-12-08 21:39:02
【问题描述】:

我有一个正在尝试进行单元测试的 MVC 3 应用程序。我从this page 中阅读了示例,该示例显示了如何模拟控制器。这是我的测试代码:

 [TestMethod]
    public void TestAddStudy() {
        var controller = new AdminController();
        var httpContext = FakeHttpContext();
        var context = new ControllerContext(new RequestContext(httpContext, new RouteData()), controller);
        controller.ControllerContext = context;

        var request = Mock.Get(controller.Request);
        request.Setup(r => r.Form).Returns(delegate() {
            var nv = new FormCollection();
            nv.Add("Name", "Test Study");
            nv.Add("IsDefault", "selected");
            return nv;
        });

        var result = controller.CreateStudy(request.Object.Form as FormCollection) as ActionResult;

    }

    public static HttpContextBase FakeHttpContext() {
        var httpContext = new Mock<HttpContextBase>();
        var request = new Mock<HttpRequestBase>();
        var response = new Mock<HttpResponseBase>();
        var session = new Mock<HttpSessionStateBase>();
        var server = new Mock<HttpServerUtilityBase>();

        httpContext.Setup(ctx => ctx.Request).Returns(request.Object);
        httpContext.SetupGet(ctx => ctx.Request.RequestType).Returns("POST");
        httpContext.Setup(ctx => ctx.Response).Returns(response.Object);
        httpContext.Setup(ctx => ctx.Session).Returns(session.Object);
        httpContext.Setup(ctx => ctx.Server).Returns(server.Object);
        httpContext.SetupGet(ctx => ctx.User.Identity.Name).Returns("testClient");

        return httpContext.Object;
    }

这是控制器内部的代码:

[HttpPost]
    public ActionResult CreateStudy(FormCollection form) {
        Study newStudy = new Study();
        TryUpdateModel(newStudy);
        newStudy.CreatedBy = CurrentUser;
        newStudy.CreatedOn = DateTime.Now;
        studyRepository.Edit(newStudy, CurrentUser);
        return RedirectToAction("EditStudy", new { id = 1 });
    }

每次在 TryUpdateModel 语句上失败,对象引用未设置为对象错误的实例。我做错了什么......或者更重要的是,我怎样才能对这个简单的方法进行单元测试?

堆栈跟踪: 在 Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.CollectionReplacer.GetUnvalidatedCollections(HttpContext 上下文) 在 Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.GetUnvalidatedCollections(HttpContext 上下文,Func1&amp; formGetter, Func1& queryStringGetter) 在 System.Web.Helpers.Validation.Unvalidated(HttpRequest 请求) 在 System.Web.Mvc.FormValueProviderFactory.<.ctor>b_0(ControllerContext cc) 在 System.Web.Mvc.FormValueProviderFactory.GetValueProvider(ControllerContext controllerContext) 在 System.Web.Mvc.ValueProviderFactoryCollection.c_DisplayClassc.b__7(ValueProviderFactory 工厂) 在 System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext() at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext() 在 System.Collections.Generic.List1..ctor(IEnumerable1 集合) 在 System.Linq.Enumerable.ToList[TSource](IEnumerable`1 源) 在 System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext) 在 System.Web.Mvc.ControllerBase.get_ValueProvider() 在 System.Web.Mvc.Controller.TryUpdateModel[TModel](TModel 模型) 在 C:\Visual Studio Projects\Controllers\AdminController.cs:line 254 中的 Controllers.AdminController.CreateStudy(FormCollection form) 在 C:\Visual Studio Projects\Tests\UnitTest1.cs:line 32 中的 Tests.UnitTest1.TestAddStudy() 处

【问题讨论】:

标签: .net asp.net-mvc-3 unit-testing


【解决方案1】:

这行实际上是返回一个对象还是为空?

Study currentStudy = ctx.Studies.Where(p => p.StudyID == id).FirstOrDefault();

您可能希望在调用 TryUpdateModel(currentStudy) 之前检查 null,如下所示:

Study currentStudy = ctx.Studies.Where(p => p.StudyID == id).FirstOrDefault();
if (currentStudy != null) {
    TryUpdateModel(currentStudy);
}

【讨论】:

  • 抱歉,发错方法了。我实际上正在研究 CreateStudy 方法。
【解决方案2】:

查看堆栈跟踪,看起来异常是在对TryUpdateModel(newStudy) 的调用中引发的。我只能想象new Study() 返回的Study 对象不满足TryUpdateModel() 的要求,或者ASP.NET MVC 需要一些依赖才能使此方法起作用,即在您的测试上下文中缺少但在您的运行时上下文中存在(假设当您运行功能测试时控制器方法对您有效)。

如果该方法在功能测试期间有效,则后一种解释必须成立。再次查看这里的堆栈跟踪:-

Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.CollectionReplacer.GetUnvalidatedCollections(HttpContext 上下文)在 Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.GetUnvalidatedCollections(HttpContext 上下文、Func1 和 formGetter、Func1 和 queryStringGetter)在 System.Web.Helpers.Validation.Unvalidated(HttpRequest request) at

看起来HttpRequest 正在用于执行某些验证。我猜您的模拟请求对象需要设置一些进一步的方法/属性返回值。特别是,我想它必须至少需要从它的FormQueryString 属性中返回NameValueCollection 实例,即使只是空的。假设 MVC 中的验证代码假设这些属性从不返回空值是合理的。鉴于您尚未在模拟对象上为这些属性设置返回值,这可以解释为什么 NullReferenceException 会在 MVC 代码的深处抛出。

尝试将这些行添加到您的模拟创建代码中:-

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

根据您的测试和/或控制器的要求,您可能会发现您必须向至少一个NameValueCollection 实例添加一些值,以便更准确地模拟真实请求的内容。

【讨论】:

  • 添加了代码,但仍然无法对其进行单元测试。奇怪的是,该方法在使用应用程序时效果很好。我似乎无法让它在单元测试中工作。
  • 你得到相同的异常和堆栈跟踪吗?
猜你喜欢
  • 1970-01-01
  • 2011-11-29
  • 2018-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-12
  • 2017-06-26
相关资源
最近更新 更多