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

Rob*_*ker 20 asp.net-mvc unit-testing

我有一个控制器,它在一个实体上实现一个简单的Add操作,并重定向到Details页面:

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

这很好用(使用MvcContrib程序集中的RedirectToAction).

当我单元测试这个方法时,我想访问从Details操作返回的ViewData(所以我可以获取新插入的东西的主键并证明它现在在数据库中).

测试有:

var result = controller.Add(thing);
Run Code Online (Sandbox Code Playgroud)

但这里的结果是类型:( System.Web.Mvc.RedirectToRouteResult这是一个System.Web.Mvc.ActionResult).它还没有执行Details方法.

我试过调用ExecuteResult返回的对象传递一个模拟,ControllerContext但框架不满意模拟对象中缺乏细节.

我可以尝试填写详细信息等,但是然后我的测试代码比我正在测试的代码更长,我觉得我需要进行单元测试的单元测试!

我错过了测试哲学中的一些东西吗?当我无法进入返回状态时,如何测试此操作?

Art*_*old 31

我现在正在使用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");
Run Code Online (Sandbox Code Playgroud)

不确定这是否会对某人有所帮助,但可能会为您节省10分钟.

  • 真棒!您可以以类似的方式检查其他路线值.对于`RedirectToAction("Details","Person",{personId = 123})`你可以检查`personId`:`Assert.AreEqual(123,actionResult.RouteValues ["personId"])` (2认同)

Cha*_*let 12

MVC Contrib TestHelper非常适合测试大多数ActionResult

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

以下是语法示例:

var controller = new TestController();

controller.Add(thing)
          .AssertActionRedirect()
          .ToAction<TestController>(x => x.Index());
Run Code Online (Sandbox Code Playgroud)

要测试数据是否已成功保存,您应该直接询问您的数据库,我不知道您是否正在使用ORM或其他东西,但是您应该做一些事情来获取数据库中最后一个已插入的项目,然后比较使用您为Add ActionResult提供的值,看看是否正常.

我不认为测试您的Details ActionResult以查看您的数据是否持久化是正确的方法.那不是单元测试,更像是功能测试.

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


rma*_*mac 7

你似乎为单元测试做了太多的事情.验证和数据访问通常由您从控制器操作调用的服务完成.你嘲笑那些服务,只测试他们被正确调用.

像这样的东西(使用Rhino.Mocks和NUnit的近似语法):

[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"));
}
Run Code Online (Sandbox Code Playgroud)


Vad*_*dim 6

我有一个静态帮助方法来测试重定向.

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]);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后创建重定向测试非常容易.

[Test]
public void ResirectionTest()
{
    var result = controller.Action();

    result.ShouldBeRedirectionTo(
        new
        {
            controller = "ControllerName",
            action = "Index"
        }
    );
}
Run Code Online (Sandbox Code Playgroud)

  • +1用于扩展方法,但由于某种原因,MVC3控制器名称为null (3认同)