24

我想测试以下代码行:

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

图片是我的模型类型 HttpPostedFileBase 中的一个属性。所以我想模拟一个用于单元测试的 HttpPostedFileBase 属性:

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

完全没有问题。

现在我必须模拟 InputStream,否则它为空:

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

这不起作用,因为 InputStream 是只读的(没有 setter 方法):

public virtual Stream InputStream { get; }

有没有一个好的和干净的方法来处理这个问题?一种解决方案是在派生类中为我的单元测试覆盖 HttpPostedFileBase。还有什么想法吗?

4

3 回答 3

36

您好 :) 我做了类似的事情,

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

        // Other stuff
    }

在测试本身上,

    [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...
    }

希望这可以为您的解决方案提供一个想法:)

于 2013-04-17T14:39:09.513 回答
16

我一直在做类似的事情,并想在@TiagoC13 的答案中添加以下内容。

我正在测试的系统是我正在编写的文件服务,其中一个要求是测试文件是否具有正确的尺寸。请注意,硬编码的文件名。这在我的测试项目中作为文件夹和文件存在。该文件的属性如下: Build Action : Embedded Resource and Copy to Output Directory: Copy if newer (尽管 Copy Always 应该可以正常工作)

构建项目后,testimage.jpg 及其文件夹将添加到测试找到它的 bin 中。

还要注意 fileStream.Close(); 这将释放文件,因此您可以在同一个套件中进行许多类似的测试。

希望这是有帮助的。

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();
    }
于 2014-04-24T15:56:22.940 回答
9

无需通过打开磁盘上的文件来创建流。实际上,我认为这是一个非常可怕的解决方案。可以在内存中轻松创建工作测试流。

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   
}        
于 2014-08-18T15:38:42.287 回答