我有一个Mock挑战 - 我正在使用MVC 3和nunit框架,并且尝试模拟控制器有一个HttpPostedFileBase作为参数。控制器签名如下所示:
public ActionResult UploadAttachment(AttachmentViewModel clientAttachment, HttpPostedFileBase file, string clientName)
我为我的“文件”参数设置了一个模拟参考,但它抱怨它不会采用模拟对象。我猜我需要为这个场景设置一个ControllerContext,但我也没有任何运气。对于第一个测试,我只需要HttpPostedFileBase返回一个空文件(在空白文件引用进入的情况下)。我还阅读了Scott Hanselman关于这个主题的优秀文章(computer Zen)。对于我关注的MVC部分中的关键句似乎是“当你创建自己的ControllerContext时,你将在Web服务器外部运行时(例如在测试中)获得动态生成的HttpRequestBase的Mock。”这似乎是我遇到墙壁的地方。
我知道我需要这些元素:
controller.ControllerContext = new ControllerContext(mockContext.Object, new RouteData(), controller);
mockContext.SetupGet(c => c.Request).Returns(mockRequest.Object);
mockRequest.Setup(c => c.HttpMethod).Returns([not sure what to evoke here]);
我处于被困状态。感谢您提出正确方向的建议或推动。
答案 0 :(得分:7)
假设您使用的是真实视图模型(由控制器操作使用,而不是使用大量参数):
public class MyViewModel
{
public HttpPostedFileBase File { get; set; }
// those won't be used in my example but you get the point
public string ClientName { get; set; }
public AttachmentViewModel ClientAttachment { get; set; }
}
以及一个您正在尝试进行单元测试的操作的控制器:
public class HomeController : Controller
{
[HttpPost]
public ActionResult UploadAttachment(MyViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var file = Path.Combine(Server.MapPath("~/App_Data"), model.File.FileName);
model.File.SaveAs(file);
return RedirectToAction("succes");
}
}
你现在要处理2起案件:
让我们滚动:
[TestMethod]
public void UploadAttachment_Should_Return_View_If_ModelState_Is_Not_Valid()
{
// arrange
var sut = new HomeController();
var model = new MyViewModel();
sut.ModelState.AddModelError("file", "please select a file");
// act
var actual = sut.UploadAttachment(model);
// assert
Assert.IsInstanceOfType(actual, typeof(ViewResult));
}
当然是第二种情况:
[TestMethod]
public void UploadAttachment_Should_Save_File_If_Model_Is_Valid_And_Redirect()
{
// arrange
var sut = new HomeController();
var file = new Mock<HttpPostedFileBase>();
file.Setup(x => x.FileName).Returns("foo.txt");
var model = new MyViewModel
{
File = file.Object
};
var server = new Mock<HttpServerUtilityBase>();
server.Setup(x => x.MapPath("~/App_Data")).Returns(@"c:\wwwroot\App_Data");
var httpContext = new Mock<HttpContextBase>();
httpContext.Setup(x => x.Server).Returns(server.Object);
sut.ControllerContext = new ControllerContext(httpContext.Object, new RouteData(), sut);
// act
var actual = sut.UploadAttachment(model);
// assert
Assert.IsInstanceOfType(actual, typeof(RedirectToRouteResult));
file.Verify(x => x.SaveAs(@"c:\wwwroot\App_Data\foo.txt"));
}
希望这会让你走上正轨。对不起,它使用MSTest而不是NUnit,但端口应该不仅仅是微不足道的(不应该超过30个工作秒)。将[TestMethod]
替换为[Test]
,您不应远离目标。是的,我打赌2 {这个{{1}}在NUnit中具有相同的效果。