2009-11-10 51 views
1

我想单元测试使用UpdateModel的控制器操作,但我没有正确地模拟HttpContext。我不断收到以下例外情况:如何伪造ASP.Net MVC的UpdateModel?

System.InvalidOperationException:上一个方法'HttpRequestBase.get_Form();'需要返回值或抛出异常。

嘲笑HttpContext我正在使用一些类似于scott posted for Rhino mocks的东西。

我添加了一个我认为会模拟'HttpRequestBase.get_Form();'的方法

public static void SetupRequestForm(this HttpRequestBase request, NameValueCollection nameValueCollection) 
{ 
    if (nameValueCollection == null) 
     throw new ArgumentNullException("nameValueCollection"); 
    SetupResult.For(request.PathInfo).Return(string.Empty); 
    SetupResult.For(request.Form).Return(nameValueCollection); 
} 

下面是单元测试:

[Authorize] 
[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Edit(int id, FormCollection collection) 
{ 
    var campaign = Campaign.GetCampaign(id); 

    if (campaign == null) 
     return View("Error", ViewData["message"] = "Oops, could not find your requested campaign."); 
    if (!campaign.CanEdit(User.Identity.Name)) 
     return View("Error", ViewData["message"] = "You are not authorized to edit this campaign style."); 

    var style = campaign.GetStyle(); 
    //my problem child for tests. 
    UpdateModel(style); 

    if (!style.IsValid) 
    { 
     ModelState.AddModelErrors(style.GetRuleViolations()); 
     return View("Edit", style); 
    } 

    style.Save(User.Identity.Name); 
    return RedirectToAction("Index", "Campaign", new { id }); 
} 

我会接受正确修改我的SetupRequestForm任何回答,单元测试,或张贴在:

[Test] 
public void Edit_GivenFormsCollection_CanPersistStyleChanges() 
{ 
    //in memory db setup omitted ... 

    var nameValueCollection = new NameValueCollection(); 
    InitFormCollectionWithSomeChanges(nameValueCollection, style); 
    var httpContext = _mock.FakeHttpContext(); 
    _mock.SetFakeControllerContext(controller, httpContext); 
    httpContext.Request.SetupRequestForm(nameValueCollection); 

    controller.Edit(1, new FormCollection(nameValueCollection)); 

    var result = (ViewResult)controller.Edit(1); 

    Assert.IsNotNull(result.ViewData); 
    style = Style.GetStyle(1); 
    AsserThatModelCorrectlyPersisted(style); 

} 

下测试控制器动作例如如何使用MVCContrib项目中的测试助手来实现相同的目标。

+0

鉴于这样的复杂性,你肯定不想只用一个强类型的ViewData对象? – 2009-11-10 00:43:20

+0

传递给获取视图的模型是强类型的。我不知道你可以发布一个强类型模型的行动。 – Aaron 2009-11-10 00:49:01

+0

ViewData [“message”]与错误视图一起使用,用于在出现错误时发送消息的通用共享视图。 – Aaron 2009-11-10 00:55:43

回答

3

您没有使用传递给您的操作方法的FormCollection。您通常在FormCollection中传递的原因是通过打破HttpConext上的UpdateModel依赖性来帮助进行测试。

所有你需要做的是改变你的UpdateModel行:

UpdateModel(style, collection.ToValueProvider()); 

一旦你这样做,你可以有关设置模拟的HttpContext忘记。例如。测试现在可以读出:

[Test] 
public void Edit_GivenFormsCollection_CanPersistStyleChanges() 
{ 
    //Blah 

    var nameValueCollection = new NameValueCollection(); 
    InitFormCollectionWithSomeChanges(nameValueCollection, style); 
    //Removed stuff 

    controller.Edit(1, new FormCollection(nameValueCollection)); 

    //Blah 
} 

HTHS,
查尔斯

+0

我仍然需要嘲笑HttpContext做User.Identity调用,但你是钱。 – Aaron 2009-11-10 02:15:41

+0

真实的......没有注意到User.Identity电话:-) – Charlino 2009-11-10 02:33:08