Sto usando Moq & NUnit come framework di test unitario.Come installare un NetworkStream in un test di unità?
Ho scritto un metodo che viene dato un oggetto NetworkStream come parametro:
public static void ReadDataIntoBuffer(NetworkStream networkStream, Queue dataBuffer)
{
if ((networkStream != null) && (dataBuffer != null))
{
while (networkStream.DataAvailable)
{
byte[] tempBuffer = new byte[512];
// read the data from the network stream into the temporary buffer
Int32 numberOfBytesRead = networkStream.Read(tempBuffer, 0, 512);
// move all data into the main buffer
for (Int32 i = 0; i < numberOfBytesRead; i++)
{
dataBuffer.Enqueue(tempBuffer[i]);
}
}
}
else
{
if (networkStream != null)
{
throw new ArgumentNullException("networkStream");
}
if (dataBuffer != null)
{
throw new ArgumentNullException("dataBuffer");
}
}
}
Ora sto guardando ri-scrittura di mio test di unità per questo metodo dal momento che le prove scritte in precedenza si basano su reali NetworkStream oggetti e non sono molto piacevoli da gestire
Come posso prendere in giro il NetworkStream? Sto usando Moq come accennato in precedenza. È possibile a tutti? In caso contrario, come posso risolvere questo problema?
In attesa di un vostro feedback!
Ecco la precedente soluzione:
public static void ReadDataIntoBuffer(Stream dataStream, Queue dataBuffer)
{
if ((networkStream != null) && (dataBuffer != null))
{
byte[] tempBuffer = new byte[512];
Int32 numberOfBytesRead = 0;
// read the data from the network stream into the temporary buffer
while ((numberOfBytesRead = dataStream.Read(tempBuffer, 0, 512) > 0)
{
// move all data into the main buffer
for (Int32 i = 0; i < numberOfBytesRead; i++)
{
dataBuffer.Enqueue(tempBuffer[i]);
}
}
}
else ...
}
UPDATE:
ho ri-scritto la mia classe, ancora una volta. Il test delle unità utilizzando la soluzione precedente è andato bene, ma l'esempio dell'applicazione reale mi ha mostrato perché NON è possibile che io usi il (altrimenti ottimo) suggerimento di passare un oggetto Stream
nel mio metodo.
Prima di tutto, la mia applicazione si basa su una connessione TCP costante. Se si utilizza Stream.Read
(che è possibile) e non ci sono dati da ricevere, bloccherà l'esecuzione. Se si specifica un timeout, verrà generata un'eccezione se non viene ricevuto alcun dato. Questo tipo di comportamento non è accettabile per l'applicazione (piuttosto semplice) di cui ho bisogno. Ho solo bisogno di una connessione TCP senza fronzoli e costante. Pertanto, la proprietà NetworkStream.DataAvailable
è fondamentale per la mia implementazione.
La soluzione attuale:
ho finito per scrivere un'interfaccia e un wrapper per NetworkStream. Ho anche finito per passare l'array di byte per il buffer di ricezione temporaneo nel metodo. L'unità di test funziona ora piuttosto bene.
public static void ReadDataIntoBuffer(INetworkStream networkStream, Queue dataBuffer, byte[] tempRXBuffer)
{
if ((networkStream != null) && (dataBuffer != null) && (tempRXBuffer != null))
{
// read the data from the network stream into the temporary buffer
while(networkStream.DataAvailable)
{
Int32 numberOfBytesRead = networkStream.Read(tempRXBuffer, 0, tempRXBuffer.Length);
// move all data into the main buffer
for (Int32 i = 0; i < numberOfBytesRead; i++)
{
dataBuffer.Enqueue(tempRXBuffer[i]);
}
}
}
else ...
}
Ed ecco la prova di unità che uso:
public void TestReadDataIntoBuffer()
{
var networkStreamMock = new Mock<INetworkStream>();
StringBuilder sb = new StringBuilder();
sb.Append(_testMessageConstant1);
sb.Append(_testMessageConstant2);
sb.Append(_testMessageConstant3);
sb.Append(_testMessageConstant4);
sb.Append(_testMessageConstant5);
// ARRANGE
byte[] tempRXBuffer = Encoding.UTF8.GetBytes(sb.ToString());
// return true so that the call to Read() is made
networkStreamMock.Setup(x => x.DataAvailable).Returns(true);
networkStreamMock.Setup(x => x.Read(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<int>())).Callback(() =>
{
// after the call to Read() re-setup the property so that we
// we exit the data reading loop again
networkStreamMock.Setup(x => x.DataAvailable).Returns(false);
}).Returns(tempRXBuffer.Length);
Queue resultQueue = new Queue();
// ACT
ReadDataIntoBuffer(networkStreamMock.Object, resultQueue, tempRXBuffer);
// ASSERT
Assert.AreEqual(Encoding.UTF8.GetBytes(sb.ToString()), resultQueue.ToArray());
}
Puoi cambiare il 'NetworkStream' in un' Stream'? Questo potrebbe rendere le cose più facili. –
Credo di poterlo fare. Puoi approfondire come ciò renderebbe le cose più facili? Moq può deridere un oggetto Stream? –
sì, Moq può simulare uno stream poiché è una classe astratta, tuttavia 'Stream' non contiene la proprietà' DataAvailable', quindi suggerisco di utilizzare l'approccio che ho descritto di seguito. –