Я использую Moq & NUnit как единый тестовый фреймворк.Как moq NetworkStream в модульном тесте?
Я написал метод, который дается объект 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());
}
Вы можете изменить 'NetworkStream' в' Stream'? Это может облегчить ситуацию. –
Думаю, я мог бы это сделать. Можете ли вы объяснить, как это облегчит ситуацию? Может ли Moq издеваться над объектом Stream? –
Да, Moq может издеваться над потоком, поскольку он является абстрактным классом, однако 'Stream' не содержит свойство DataAvailable', поэтому я предлагаю вам использовать подход, который я изложил ниже. –