TDD и высмеивание TcpClient
-
02-07-2019 - |
Вопрос
Как люди подходят к издевательству над TcpClient (или такими вещами, как TcpClient)?
У меня есть сервис, который принимает TcpClient.Должен ли я обернуть это во что-то другое, более издевательское?Как мне следует подойти к этому?
Решение
При переходе к макетным классам, которые не подходят для тестирования (т.е.запечатанный / не реализующий какой-либо интерфейс / методы не являются виртуальными), вы, вероятно, захотите использовать Адаптер шаблон проектирования.
В этом шаблоне вы добавляете класс переноса, который реализует интерфейс.Затем вы должны смоделировать интерфейс и убедиться, что весь ваш код использует этот интерфейс вместо недружественного конкретного класса.Это выглядело бы примерно так:
public interface ITcpClient
{
Stream GetStream();
// Anything you need here
}
public class TcpClientAdapter: ITcpClient
{
private TcpClient wrappedClient;
public TcpClientAdapter(TcpClient client)
{
wrappedClient = client;
}
public Stream GetStream()
{
return wrappedClient.GetStream();
}
}
Другие советы
Я думаю, что @Hitchhiker на правильном пути, но мне также нравится думать о том, чтобы абстрагироваться от подобных вещей еще на шаг.
Я бы не стал издеваться над TcpClient напрямую, потому что это все равно слишком тесно привязало бы вас к базовой реализации, даже если вы написали тесты.То есть ваша реализация привязана конкретно к методу TcpClient.Лично я бы попробовал что-то вроде этого:
[Test]
public void TestInput(){
NetworkInputSource mockInput = mocks.CreateMock<NetworkInputSource>();
Consumer c = new Consumer(mockInput);
c.ReadAll();
// c.Read();
// c.ReadLine();
}
public class TcpClientAdapter : NetworkInputSource
{
private TcpClient _client;
public string ReadAll()
{
return new StreamReader(_tcpClient.GetStream()).ReadToEnd();
}
public string Read() { ... }
public string ReadLine() { ... }
}
public interface NetworkInputSource
{
public string ReadAll();
public string Read();
public string ReadLine();
}
Эта реализация полностью отделит вас от деталей, связанных с Tcp (если это является целью разработки), и вы даже можете передавать тестовые входные данные из жестко закодированного набора значений или тестового входного файла.Очень удобно, если вы находитесь на пути к длительному тестированию своего кода.
Использование шаблона адаптера, безусловно, является стандартным подходом TDD к решению проблемы.Однако вы могли бы также просто создать другой конец TCP-соединения и запустить его с помощью тестового жгута проводов.
IMO широкое использование класса adapter запутывает наиболее важные части дизайна, а также приводит к удалению из процесса тестирования многих материалов, которые действительно должны быть протестированы в контексте.Таким образом, альтернативой является создание тестовых каркасов, включающих в себя больше тестируемой системы.Если вы создаете свои тесты с нуля, вы все равно получите возможность изолировать причину сбоя для данного класса или функции, просто это не будет происходить изолированно...