Using Request.Files.Count with TestControllerBuilder from MvcContrib?
-
05-07-2019 - |
Question
I have a controller action in ASP.NET MVC that handles uploaded files. However, it seems there is no way to call Request.Files.Count
while using MvcContrib's TestControllerBuilder
.
I know I can work around this by abstracting Request.Files
. My questions are:
- Is it indeed the case that there is no direct way to call
Request.Files.Count
when using theTestControllerBuilder
? Or am I doing something wrong? - Is there a way to stub the call to
Request.Files.Count
while usingTestControllerBuilder
using Rhino Mocks? - Do you think I should submit a request or patch for handling
Request.Files.Count
to MvcContrib?
Example code:
I want to make sure that there is at least one file in the Request.Files
collection so I have the following conditional in my action:
public class MyController : Controller {
public ActionResult Upload() {
if (Request.Files == null || Request.Files.Count == 0)
ViewData.ModelState.AddModelError("File", "Please upload a file");
// do stuff
return View();
}
}
I am using the TestControllerBuilder
from MvcContrib to create the test double for my controller tests. However, the call to Request.Files.Count
always seems to throw a an exception. For example running the following NUnit test throws a NotImplementedException
during the call to controller.Upload()
at the call to Request.Files.Count
:
[Test]
public void Upload_should_return_default_view_given_one_file() {
MyController controller = new MyController();
TestControllerBuilder controllerBuilder = new TestControllerBuilder();
controllerBuilder.InitializeController(controller);
controllerBuilder.Files["file"] =
MockRepository.GenerateStub<HttpPostedFileBase>();
var result = controller.Upload() as ViewResult;
Assert.That(result.ViewData.ModelState.IsValid, Is.True);
result.AssertViewRendered().ForView(string.Empty);
}
I've also attempted stubbing the call to Request.Files.Count
to no avail (I'm using Rhino Mocks). None of the below work (even if I change controller
and/or controllerBuilder
to a stub):
controllerBuilder.Stub(cb => cb.HttpContext.Request.Files.Count).Return(1);
controller.Stub(c => c.Request.Files.Count).Return(1);
Thanks
Solution
I submitted a patch on Github to MvcContrib mantainers, but the changes are very simple to make, the problem is that HttpFileCollectionBase is not implementing Count() and this[int index] methods so they must be overriden by the WriteableHttpFileCollection in MvcContrib.
I paste the code here for completeness, that must be added to WriteableHttpFileCollection class:
public override HttpPostedFileBase this[int index]
{
get { return files[AllKeys[index]]; }
}
public override int Count
{
get { return files.Count; }
}
OTHER TIPS
I've used this approach to solve the problem.
SetUp the test: string fileName = "Test 1.pdf"; FileStream stream = File.OpenRead("log4net.config"); MockRepository mock = new MockRepository();
builder.Files[fileName] = mock.CreateMock<HttpPostedFileBase>();
using (mock.Record())
{
Expect.Call(builder.Files[fileName].FileName)
.Return(fileName);
Expect.Call(builder.Files[fileName].ContentType)
.Return(contentType);
Expect.Call(builder.Files[fileName].ContentLength)
.Return(Convert.ToInt32(stream.Length.ToString()));
Expect.Call(builder.Files[fileName].InputStream)
.Return(stream);
}
using the mock:
foreach(string key in Request.Files.AllKeys)
{
int lenght = Request.Files[key].ContentLength;
if (lenght > 0)
{
Document document = new Document();
string fileName = Request.Files[key].FileName;
byte[] content= new byte[Convert.ToInt32(lenght)];
Request.Files[key].InputStream.Read(content, 0, content.Length);
document.SetContent(content);
document.MimeType = Request.Files[key].ContentType;
// do whatever you want...
}
}