Как к moq NetworkStream в модульном тесте?

Я использую 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 ...
}

ОБНОВЛЕНИЕ:

Я переписал свой класс еще раз. Поблочное тестирование с помощью предыдущего решения пошло прекрасное, но реальный пример приложения показал мне, почему для меня не возможно использовать (в других отношениях большое) предложение передачи a 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());
}
16
задан Timo Kosig 5 February 2010 в 11:32
поделиться

3 ответа

Вы не можете издеваться от NetworkStream с MOQ, поскольку он не является абстрактным классом или интерфейсом. Однако вы можете создать абстракцию поверх него и изменить свой способ, чтобы принять экземпляр этой абстракции. Это может быть что-то вроде этого:

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

Теперь вы создаете класс, который реализует интерфейс:

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

}

Теперь вы можете изменить свой метод подпись для использования экземпляра IMYNETWorkStream и используйте MOQ для создания макета IMynetWorkStream .

17
ответ дан 30 November 2019 в 21:45
поделиться

Поместите сеть позади простой интерфейс (только с нужными вами звонками) и издевательства.

1
ответ дан 30 November 2019 в 21:45
поделиться

Как предложено в комментариях - возможно ли вам изменить тип для потока, чтобы вы, во время тестирования, вместо этого можно пройти память?

6
ответ дан 30 November 2019 в 21:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: