Я использую Moq & NUnit в качестве основы для модульного тестирования.
Я написал метод, которому в качестве параметра передается объект NetworkStream:
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");
}
}
}
Теперь я планирую переписать свои модульные тесты для этого метода, поскольку ранее написанные тесты основаны на реальных объектах NetworkStream и не очень удобны в обращении.
Как я могу издеваться над NetworkStream? Я использую Moq, как упоминалось ранее. Это вообще возможно? Если нет, то как я мог обойти эту проблему?
Ждем ваших отзывов!
Вот
предыдущее решение:
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:
Я переписал свой класс еще раз. Модульное тестирование с использованием предыдущего решения прошло нормально, но пример реального приложения показал мне, почему я НЕ могу использовать (в противном случае отличный) совет о передаче объекта Stream
в мой метод.
Во-первых, мое приложение использует постоянное TCP-соединение. Если вы используете Stream.Read
(что возможно) и нет данных для получения, это заблокирует выполнение. Если вы укажете тайм-аут, будет сгенерировано исключение, если данные не получены. Такое поведение неприемлемо для (довольно простого) приложения, которое мне нужно. Мне просто нужно без излишеств, постоянное соединение TCP. Поэтому наличие свойства NetworkStream.DataAvailable
имеет первостепенное значение для моей реализации.
Текущее решение :
В итоге я написал интерфейс и оболочку для NetworkStream. Я также закончил тем, что передал байтовый массив для временного буфера приема в метод. Модульное тестирование теперь работает довольно хорошо.
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 ...
}
А вот юнит-тест, который я использую:
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());
}