Издевательский HttpPostedFileBase и InputStream для unit-test
Я хочу протестировать следующую строку кода:
...
Bitmap uploadedPicture = Bitmap.FromStream(model.Picture.InputStream) as Bitmap;
...
Изображение является свойством в моей модели HttpPostedFileBase.
Поэтому я хотел бы высмеять свойство HttpPostedFileBase для модульного тестирования:
model.Picture = new Mock<HttpPostedFileBase>().Object;
Нет проблем.
Теперь я должен издеваться над InputStream, иначе это будет null:
model.Picture.InputStream = new Mock<Stream>().Object;
Это не работает, поскольку InputStream доступен только для чтения (не имеет метода setter):
public virtual Stream InputStream { get; }
Есть ли хороший и чистый способ справиться с этой проблемой?
Одним из решений было бы переопределить HttpPostedFileBase в производном классе для моего модульного теста.
Любая другая идея?
Ответы
Ответ 1
Привет там:) Я сделал что-то вроде:
[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...
}
Надеюсь, это может дать вам идею:)
Ответ 2
Я только что работал над чем-то похожим и хотел добавить следующее к ответу @TiagoC13.
Моя тестируемая система была файловой службой, которую я пишу, одним из требований является проверка того, что файл имеет правильные размеры. Обратите внимание, жестко закодированное имя файла. Это существует как папка и файл в моем тестовом проекте. Свойства файла следующие: Build Action: Embedded Resource and Copy to Output Directory: копировать, если он более новый (хотя Copy Always должен работать нормально)
Когда проект построен, testimage.jpg и его папка добавляются в корзину, где тест затем находит ее.
Также обратите внимание на файлStream.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();
}
Ответ 3
Нет необходимости создавать поток при открытии файла на диске. На самом деле я считаю это довольно ужасным решением. Рабочий тестовый поток может быть создан достаточно легко в памяти.
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
}