Comment créer un NetworkStream dans un test unitaire?

J’utilise Moq & NUnit en tant que framework de test unitaire.

J’ai écrit une méthode à laquelle un object NetworkStream est atsortingbué:

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"); } } } 

Je cherche maintenant à réécrire mes tests unitaires pour cette méthode car les tests précédemment écrits reposent sur de véritables objects NetworkStream et ne sont pas très agréables à gérer.

Comment puis-je me moquer du NetworkStream? J’utilise Moq comme mentionné auparavant. Est-ce possible? Sinon, comment puis-je résoudre ce problème?

Dans l’attente de vos commentaires!

Voici la solution précédente:

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

METTRE À JOUR:

J’ai réécrit ma classe une fois de plus. Les tests unitaires utilisant la solution précédente se sont bien déroulés, mais l’exemple d’application réel m’a montré pourquoi il m’est IMPOSSIBLE d’utiliser la suggestion (sinon géniale) de passer un object Stream à ma méthode.

Tout d’abord, mon application repose sur une connexion TCP constante. Si vous utilisez Stream.Read (ce qui est possible) et qu’il n’y a aucune donnée à recevoir, cela bloquera l’exécution. Si vous spécifiez un délai d’expiration, une exception sera levée si aucune donnée n’est reçue. Ce type de comportement n’est pas acceptable pour l’application (plutôt simple) dont j’ai besoin. J’ai juste besoin d’une connexion TCP constante et sans fioritures. Par conséquent, avoir la propriété NetworkStream.DataAvailable est primordial pour mon implémentation.

La solution actuelle:

J’ai fini par écrire une interface et un wrapper pour NetworkStream. J’ai également fini par passer le tableau d’octets pour le tampon de réception temporaire dans la méthode. Les tests unitaires fonctionnent plutôt bien maintenant.

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

Et voici le test unitaire que j’utilise:

 public void TestReadDataIntoBuffer() { var networkStreamMock = new Mock(); SsortingngBuilder sb = new SsortingngBuilder(); sb.Append(_testMessageConstant1); sb.Append(_testMessageConstant2); sb.Append(_testMessageConstant3); sb.Append(_testMessageConstant4); sb.Append(_testMessageConstant5); // ARRANGE byte[] tempRXBuffer = Encoding.UTF8.GetBytes(sb.ToSsortingng()); // return true so that the call to Read() is made networkStreamMock.Setup(x => x.DataAvailable).Returns(true); networkStreamMock.Setup(x => x.Read(It.IsAny(), It.IsAny(), It.IsAny())).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.ToSsortingng()), resultQueue.ToArray()); } 

Vous ne pouvez pas vous moquer de NetworkStream avec moq puisqu’il ne s’agit ni d’une classe abstraite ni d’une interface. Vous pouvez cependant créer une abstraction par-dessus et modifier votre méthode pour accepter une instance de cette abstraction. Cela pourrait être quelque chose comme ça:

 public interface IMyNetworkStream { int Read([In, Out] byte[] buffer, int offset, int size); bool DataAvailable {get;} } 

Maintenant, vous créez une classe qui implémente l’interface:

 public class MyNetworkStream : IMyNetworkStream { private NetworkStream stream; public MyNetworkStream(NetworkStream ns) { if(ns == null) throw new ArgumentNullException("ns"); this.stream = ns; } public bool DataAvailable { get { return this.stream.DataAvailable; } } public int Read([In, Out] byte[] buffer, int offset, int size) { return this.stream.Read(buffer, offset, size); } } 

Vous pouvez maintenant modifier la signature de votre méthode pour utiliser une instance de IMyNetworkStream et utiliser Moq pour créer une maquette de IMyNetworkStream .

Comme suggéré dans les commentaires, est-il possible pour vous de changer le type en Stream pour que vous puissiez passer un MemoryStream à la place pendant le test?

Placez le NetworkStream derrière une interface simple (avec uniquement les appels dont vous avez besoin) et simulez-le.