2013-03-25 15 views
15

voglio testare la seguente riga di codice:derisione HttpPostedFileBase e InputStream per l'unità-test

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

Picture è una struttura nel mio tipo di modello HttpPostedFileBase. quindi vorrei prendere in giro una proprietà HttpPostedFileBase per l'unità-test:

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

Nessun problema a tutti.

Ora devo prendere in giro l'InputStream, altrimenti è nullo:

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

Questo non funziona come l'InputStream è di sola lettura (non ha un metodo setter):

public virtual Stream InputStream { get; } 

C'è un modo buono e pulito per gestire questo problema? Una soluzione sarebbe quella di sovrascrivere HttpPostedFileBase in una classe derivata per il mio unit test. Qualche altra idea?

risposta

29

Ciao :) Ho fatto qualcosa di simile,

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

     // Other stuff 
    } 

E sulla prova stessa,

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

Spero che questo può fornire un'idea per la vostra soluzione :)

+1

L'ho fatto in modo abbastanza simile, quindi contrassegno la risposta come corretta. – mosquito87

11

I' Ho appena lavorato su qualcosa di simile e volevo aggiungere quanto segue alla risposta di @ TiagoC13.

Il mio sistema in prova era un servizio file che sto scrivendo, uno dei requisiti è verificare che un file abbia le dimensioni corrette. Nota, il nome file hard-coded. Esiste come una cartella e un file nel mio progetto di test. Le proprietà del file sono le seguenti: Build Action: Embedded Resource e Copy to Output Directory: Copia se più recente (anche se Copy Always dovrebbe funzionare OK)

Quando il progetto viene creato, witnessage.jpg e la sua cartella vengono aggiunti al cestino dove il test poi lo trova.

Nota anche il fileStream.Close(); questo rilascia il file in modo da poter avere un numero di test simili nella stessa suite.

Spero che questo sia di aiuto.

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

mi ha aiutato :) –

7

Non è necessario creare un flusso dall'apertura di un file su disco. In realtà penso che sia una soluzione piuttosto orribile. Un flusso di prova funzionante può essere creato facilmente in memoria.

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

Questo diventa un test unitario invece di un test di integrazione come soluzione di Daniel. È bello, non sapevo che potresti tirarlo fuori in questo modo, ma questo è meno leggibile (anche se sono d'accordo che potresti riuscire a riutilizzare il codice nei tuoi test). Non sei sicuro di cosa sia così orribile per l'altro oltre a dover avere un'immagine nel progetto di test. Non è peggio di avere un database per i test di integrazione ... –

+0

@fearofawhackplanet! – csharpsql

+1

@FabioMilheiro è orribile perché l'OP sta chiedendo specificatamente dei test delle unità, e un test di unità non dovrebbe dipendere dal file system fisico. – fearofawhackplanet