2013-03-25 32 views
15

Chcę przetestować następujący wiersz kodu:Mocking HttpPostedFileBase i InputStream do jednostki testu

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

obraz jest nieruchomość w swoim rodzaju modelu HttpPostedFileBase. Więc chciałbym mock właściwość HttpPostedFileBase dla testów jednostkowych:

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

Nie ma problemu w ogóle.

Teraz muszę kpić z InputStream, w przeciwnym razie jest zerowy:

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

To nie działa jako InputStream jest tylko do odczytu (nie ma sposobu setter):

public virtual Stream InputStream { get; } 

Czy istnieje dobry i czysty sposób na rozwiązanie tego problemu? Jednym z rozwiązań byłoby nadpisanie HttpPostedFileBase w klasie pochodnej dla mojego testu jednostkowego. Każdy inny pomysł?

Odpowiedz

29

Cześć :) Zrobiłem coś,

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

     // Other stuff 
    } 

A na samym teście,

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

Nadzieja ta może stanowić pomysł rozwiązania :)

+1

Zrobiłem to całkiem podobnie, więc zaznaczam twoją odpowiedź jako poprawną. – mosquito87

11

I” Właśnie pracowałem nad czymś podobnym i chciałem dodać poniższe do odpowiedzi @ TiagoC13.

Mój system w trakcie testu był usługą plikową, którą piszę, jednym z wymogów było sprawdzenie, czy plik ma odpowiednie wymiary. Zauważ, że jest to zakodowana nazwa pliku. To istnieje jako folder i plik w moim Projekcie Testowym. Właściwości pliku są następujące: Działanie kompilacji: Osadzone zasoby i Kopiuj do katalogu wyjściowego: Kopiuj, jeśli jest nowsza (chociaż funkcja Kopiuj zawsze powinna działać poprawnie)

Po zbudowaniu projektu plik testimage.jpg i jego folder zostaną dodane do kosza gdzie test ją znajduje.

Zanotuj również plik fileStream.Close(); to zwalnia plik, dzięki czemu możesz mieć wiele podobnych testów w tym samym pakiecie.

Mam nadzieję, że to pomoże.

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(); 
    } 
+1

pomógł mi :) –

7

Nie ma potrzeby tworzenia strumienia z otwarcia pliku na dysku. Uważam, że to dość przerażające rozwiązanie. Pracujący strumień testowy można łatwo utworzyć w pamięci.

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 
}   
+2

To staje się testem jednostkowym zamiast testu integracji jako rozwiązanie Daniela. To miłe, nie wiedziałem, że możesz wyciągnąć to tak, ale ten jest mniej czytelny (chociaż zgadzam się, że możesz powtórzyć kod w twoich testach). Nie jestem pewien, co jest tak strasznego w drugim, oprócz tego, że trzeba mieć obraz w projekcie testowym. To nie jest gorsze niż posiadanie bazy danych do testów integracyjnych ... –

+0

bardzo ładne @fearofawhackplanet! – csharpsql

+1

@FabioMilheiro to okropne, ponieważ OP w szczególności pyta o testowanie jednostkowe, a test jednostkowy nie powinien być zależny od fizycznego systemu plików. – fearofawhackplanet

Powiązane problemy