我有一个控制器,它在一个实体上实现一个简单的Add操作,并重定向到Details页面:
[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
,但框架对模拟对象中缺少细节感到不满。
我可以尝试填写详细信息等,但是我的测试代码比我正在测试的代码长,我觉得我需要单元测试进行单元测试!
我在测试哲学中遗漏了什么?当我无法进入返回状态时,如何测试此操作?
答案 0 :(得分: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");
不确定这是否会对某人有所帮助,但可能会为您节省10分钟。
答案 1 :(得分: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());
要测试数据是否已成功保留,您应该直接询问您的数据库,我不知道您是否正在使用ORM或其他东西,但是您应该做些什么来获取数据库中最后一个已插入的项目,然后与您提供给Add ActionResult的值进行比较,看看是否正常。
我不认为测试您的Details ActionResult以查看您的数据是否持久化是正确的方法。那不是单元测试,更像是功能测试。
但是你也应该对你的Details方法进行单元测试,以确保你的viewdata对象充满了来自你数据库的正确数据。
答案 2 :(得分:7)
你似乎为单元测试做了太多的事情。验证和数据访问通常由您从控制器操作调用的服务完成。你嘲笑那些服务,只测试它们被正确调用。
像这样(使用Rhino.Mocks&amp; 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"));
}
答案 3 :(得分: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]);
}
}
}
然后创建重定向测试非常容易。
[Test]
public void ResirectionTest()
{
var result = controller.Action();
result.ShouldBeRedirectionTo(
new
{
controller = "ControllerName",
action = "Index"
}
);
}