代码之家  ›  专栏  ›  技术社区  ›  Rob Walker

在ASP.NET MVC 2中用RedirectToAction对控制器进行单元测试

  •  20
  • Rob Walker  · 技术社区  · 15 年前

    [HttpPost]
    public ActionResult Add(Thing thing)
    { 
        // ... do validation, db stuff ...
        return this.RedirectToAction<c => c.Details(thing.Id));
    }
    

    这非常有效(使用MvcContrib程序集的RedirectToAction)。

    当我对这个方法进行单元测试时,我想访问从Details操作返回的ViewData(这样我就可以得到新插入的东西的主键,并证明它现在在数据库中)。

    试验有:

    var result = controller.Add(thing);
    

    System.Web.Mvc.RedirectToRouteResult (这是一个 System.Web.Mvc.ActionResult ). 它还没有执行Details方法。

    我试过打电话 ExecuteResult 返回的对象传递一个模型 ControllerContext 但是框架并不满意模拟对象缺乏细节。

    我可以试着填写细节,等等,但是我的测试代码比我正在测试的代码要长得多,我觉得我需要单元测试来进行单元测试!

    我在测试理念上遗漏了什么吗?当我无法达到其返回状态时,如何测试此操作?

    4 回复  |  直到 15 年前
        1
  •  31
  •   ArtificialGold    15 年前

    我目前正在使用MVC2 RC2,rmacfie的答案对我来说不太管用,但确实让我走上了正轨。

    不管是对是错,我在考试中做到了这一点:

    var actionResult = (RedirectToRouteResult)logonController.ForgotUsername(model);
    
    actionResult.RouteValues["action"].should_be_equal_to("Index");
    actionResult.RouteValues["controller"].should_be_equal_to("Logon");
    

    不确定这是否有助于某人,但可能会节省你10分钟。

        2
  •  12
  •   Charles Ouellet    15 年前

    你可以在这里得到它: http://mvccontrib.codeplex.com/wikipage?title=TestHelper

    下面是一个语法示例:

    var controller = new TestController();
    
    controller.Add(thing)
              .AssertActionRedirect()
              .ToAction<TestController>(x => x.Index());
    

    为了测试数据是否成功持久化,您应该直接询问您的数据库,我不知道您是否在使用ORM或其他什么,但是您应该做一些事情来获取数据库中最后一个inserted项,然后与您提供给Add ActionResult的值进行比较,看看这是否正确。

    我不认为测试您的细节ActionResult以查看您的数据是否持久化是正确的方法。那不是单元测试,而是功能测试。

    但是您还应该对Details方法进行单元测试,以确保viewdata对象中填充了来自数据库的正确数据。

        3
  •  7
  •   rmac    15 年前

    对于单元测试来说,你似乎做得太多了。验证和数据访问通常由从控制器操作调用的服务完成。您模拟这些服务,只测试它们是否被正确调用。

    [Test]
    public void Add_SavesThingToDB()
    {
        var dbMock = MockRepository.GenerateMock<DBService>();
        dbMock.Expect(x => x.Save(thing)).Repeat.Once();
    
        var controller = new MyController(dbMock);
        controller.Add(new Thing());
    
        dbMock.VerifyAllExpectations();
    }
    
    [Test]
    public void Add_RedirectsAfterSave()
    {
        var dbMock = MockRepository.GenerateMock<DBService>();
    
        var controller = new MyController(dbMock);
        var result = (RedirectToRouteResult)controller.Add(new Thing());
    
        Assert.That(result.Url, Is.EqualTo("/mynew/url"));
    }
    
        4
  •  6
  •   Dan Atkinson    13 年前

    我有一个测试重定向的静态助手方法。

    public static class UnitTestHelpers
    {
        public static void ShouldEqual<T>(this T actualValue, T expectedValue)
        {
            Assert.AreEqual(expectedValue, actualValue);
        }
    
        public static void ShouldBeRedirectionTo(this ActionResult actionResult, object expectedRouteValues)
        {
            RouteValueDictionary actualValues = ((RedirectToRouteResult)actionResult).RouteValues;
            var expectedValues = new RouteValueDictionary(expectedRouteValues);
    
            foreach (string key in expectedValues.Keys)
            {
                Assert.AreEqual(expectedValues[key], actualValues[key]);
            }
        }
    }
    

    然后创建重定向测试非常简单。

    [Test]
    public void ResirectionTest()
    {
        var result = controller.Action();
    
        result.ShouldBeRedirectionTo(
            new
            {
                controller = "ControllerName",
                action = "Index"
            }
        );
    }