Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking HttpPostedFileBase and InputStream for unit-test

I want to test the following line of code:

...
Bitmap uploadedPicture = Bitmap.FromStream(model.Picture.InputStream) as Bitmap;
...

Picture is a property in my model type HttpPostedFileBase. So I would like to mock a HttpPostedFileBase property for unit-testing:

model.Picture = new Mock<HttpPostedFileBase>().Object;

No problem at all.

Now I have to mock the InputStream, otherwise it's null:

model.Picture.InputStream = new Mock<Stream>().Object;

This isn't working as the InputStream is read-only (hasn't a setter method):

public virtual Stream InputStream { get; }

Is there a good and clean way to handle this problem? One solution would be to override HttpPostedFileBase in a derived class for my unit-test. Any other idea?

like image 583
mosquito87 Avatar asked Mar 25 '13 18:03

mosquito87


3 Answers

Hi there :) I did something like,

    [TestInitialize]
    public void SetUp()
    {
        _stream = new FileStream(string.Format(
                        ConfigurationManager.AppSettings["File"],
                        AppDomain.CurrentDomain.BaseDirectory), 
                     FileMode.Open);

        // Other stuff
    }

And on the Test itself,

    [TestMethod]
    public void FileUploadTest() 
    {
        // Other stuff

        #region Mock HttpPostedFileBase

        var context = new Mock<HttpContextBase>();
        var request = new Mock<HttpRequestBase>();
        var files = new Mock<HttpFileCollectionBase>();
        var file = new Mock<HttpPostedFileBase>();
        context.Setup(x => x.Request).Returns(request.Object);

        files.Setup(x => x.Count).Returns(1);

        // The required properties from my Controller side
        file.Setup(x => x.InputStream).Returns(_stream);
        file.Setup(x => x.ContentLength).Returns((int)_stream.Length);
        file.Setup(x => x.FileName).Returns(_stream.Name);

        files.Setup(x => x.Get(0).InputStream).Returns(file.Object.InputStream);
        request.Setup(x => x.Files).Returns(files.Object);
        request.Setup(x => x.Files[0]).Returns(file.Object);

        _controller.ControllerContext = new ControllerContext(
                                 context.Object, new RouteData(), _controller);

        // The rest...
    }

Hope this can provide an idea to your solution :)

like image 93
TiagoC13 Avatar answered Oct 15 '22 07:10

TiagoC13


I've just been working on something similar and wanted to add the following to @TiagoC13's answer.

My system under test was a file service I'm writing, one of the requirements being to test that a file has the correct dimensions. Note, the hard-coded filename. This exists as a folder and file in my Test Project. The file's properties are as follows: Build Action : Embedded Resource and Copy to Output Directory: Copy if newer (although Copy Always should work OK)

When the project is built the testimage.jpg and its folder are added to the bin where the test then finds it.

Also note the fileStream.Close(); this releases the file so you can have a number of similar tests in the same suite.

Hope this is of help.

using Moq;
using NUnit.Framework;
using System.Web;

    [Test]
    public void IsValidFile() {
        string filePath = Path.GetFullPath(@"testfiles\testimage.jpg");
        FileStream fileStream = new FileStream(filePath, FileMode.Open);
        Mock<HttpPostedFileBase> uploadedFile = new Mock<HttpPostedFileBase>();

        uploadedFile
            .Setup(f => f.ContentLength)
            .Returns(10);

        uploadedFile
            .Setup(f => f.FileName)
            .Returns("testimage.jpg");

        uploadedFile
            .Setup(f => f.InputStream)
            .Returns(fileStream);

        var actual = fileSystemService.IsValidImage(uploadedFile.Object, 720, 960);

        Assert.That(actual, Is.True);

        fileStream.Close();
    }
like image 42
Daniel Hollinrake Avatar answered Oct 15 '22 06:10

Daniel Hollinrake


There is no need to create a stream from opening a file on disk. Actually I think that's a pretty horrible solution. A working test stream can be created easily enough in-memory.

var postedFile = new Mock<HttpPostedFileBase>();

using (var stream = new MemoryStream())
using (var bmp = new Bitmap(1, 1))
{
    var graphics = Graphics.FromImage(bmp);
    graphics.FillRectangle(Brushes.Black, 0, 0, 1, 1);
    bmp.Save(stream, ImageFormat.Jpeg);

    postedFile.Setup(pf => pf.InputStream).Returns(stream);

    // Assert something with postedFile here   
}        
like image 9
fearofawhackplanet Avatar answered Oct 15 '22 06:10

fearofawhackplanet