delphi клиент Как проверить класс, который подключается к FTP-серверу?




ftp клиент (4)

Просто заимствуйте демоверсию FTP или HTTP Server, которая поставляется с любым желаемым компонентом сокета, который вы предпочитаете (Indy, ICS или что-то еще). Мгновенный сервер тестирования.

Я бы поместил его в папку с инструментами для моих модульных тестов. Я могу написать код, который проверяет, является ли TestFtpServer.exe уже живым, а если нет, запустите его.

Я бы оставил его вне моего пространства памяти процесса тестирования приложения, таким образом, отдельный процесс.

Обратите внимание, что к тому времени, как вы попадаете на операции FTP-сервера, модульное тестирование действительно должно называться «интеграционным тестированием».

Я бы не вручную создавал файлы из моего модульного теста. Я бы ожидал, что мой код должен быть проверен с помощью управления версиями и, как есть, создать из пакетного файла, который запускает мою тестовую программу, которая знает о ServerData под названием «Инструменты», которая содержит EXE и, возможно, папку с именем ServerData и LocalData которые могут использоваться для хранения данных, которые начинаются на сервере и передаются в мое тестовое приложение локального устройства. Возможно, вы можете взломать ваш демонстрационный сервер, чтобы он завершил часть сеанса (когда вы хотите протестировать сбои), но я все равно не думаю, что вы получите хороший охват.

Примечание. Если вы делаете автоматические обновления, я думаю, что никакое количество модульных испытаний не сократит его. Вам нужно иметь дело с множеством потенциальных проблем, связанных с Интернетом. Что происходит, когда ваше имя хоста не разрешается? Что происходит, когда загрузка проходит частично и не удается? Автоматическое обновление не очень хорошо сочетается с возможностями модульного тестирования.

Я разрабатываю обновление для своего приложения. До сих пор я создал почти все модульные тесты, но я понятия не имею, как протестировать определенный класс, который подключается к FTP-серверу и загружает новые версии.

Чтобы протестировать этот класс, должен ли я создать тестовый сервер FTP и использовать его в своих модульных тестах? Если да, то как я могу убедиться, что этот FTP-сервер всегда соответствует моим тестам? Должен ли я вручную создавать каждый файл, который мне понадобится до начала теста, или я должен автоматизировать его в своем тестовом классе (методы срыва и настройки)?

Этот вопрос также относится к классам тестирования модулей, которые подключаются к любому серверу.

РЕДАКТИРОВАТЬ

Я уже высмеиваю свой класс ftp, поэтому мне не нужно всегда подключаться к ftp-серверу в других тестах.

Позвольте мне посмотреть, правильно ли я понял, что сказал Уоррен в своем комментарии:

Я бы сказал, что, когда вы разговариваете с отдельным приложением по TCP / IP, мы должны назвать это «интеграционными тестами». Один больше не тестирует устройство или метод, а систему.

Когда единичный тест должен связываться с другим приложением (который может быть HTTP-сервером или FTP-сервером), это уже не единичный тест, а сервер интеграции? Если это так, я делаю это неправильно, пытаясь использовать методы модульного тестирования для создания этого теста? Правильно ли говорить, что я не должен тестировать этот класс? Это имеет смысл для меня, потому что, похоже, много работы для модульного теста.


Answer #1

Модульные тесты должны быть быстрыми, быстро освещающими. Все, что замедляет их, не позволяет вам не запускать их.

Они также должны быть последовательными от одного пробега к другому. Тестирование фактической передачи файлов приведет к возможности случайных сбоев в ваших модульных тестах.

Если класс, который вы тестируете, делает не что иное, как обертывание api библиотеки ftp, которую вы используете, тогда вы достигли одной из границ вашего приложения, вам не нужно его тестировать. (Ну, иногда вы это делаете. Его называют поисковым тестированием, но обычно их отбрасывают, как только вы получаете ответ)

Если, однако, в классе есть какая-то логика, вы должны попробовать протестировать ее отдельно от фактического api. Вы делаете это, создавая обертку для ftp api. Затем в ваших модульных тестах вы создаете тестовый двойник, который может стоять в качестве замены для обертки. Существует множество вариантов, которые имеют разные названия: заглушка, подделка, макет объекта. В нижней части вы хотите убедиться, что ваши юнит-тесты изолированы от любого внешнего воздействия. Единичный тест со спорадическим поведением менее бесполезен.

Тестирование фактического механизма передачи файлов должно выполняться при тестировании интеграции, которое обычно выполняется реже, потому что оно медленнее. Даже при тестировании интеграции вы захотите попробовать как можно больше контролировать тестовую среду. (т.е. тестирование с ftp-сервером в локальной сети, которая настроена на имитацию производственного сервера).

И помните, вы никогда не поймете все впереди. Ошибки проскальзывают независимо от того, насколько хороши тесты. Просто убедитесь, что когда они это сделают, вы добавите еще один тест, чтобы поймать их в следующий раз.

Я бы рекомендовал либо купить, либо проверить копию XUnit Test Patterns Джерардом Мезаросом. Это сокровищница полезной информации о том, что / когда / как тестировать блок.


Answer #2

При тестировании цель всегда заключается в том, чтобы сначала ответить на вопрос: что тестируется - то есть объем теста.

Поэтому, если вы тестируете реализацию FTP-сервера, вам придется создать FTP-клиент.

Если вы тестируете FTP-клиент, вам придется создать FTP-сервер.

Поэтому вам придется уменьшить размер теста до тех пор, пока вы не достигнете унитарного уровня.

Это может быть, например, для вашей цели:

  • Получение списка текущих файлов, установленных для приложения;
  • Получение списка файлов, доступных удаленно;
  • Получение обновления файла;
  • Проверка правильности файла (контрольная сумма?);
  • и так далее...

Каждый испытанный предмет должен иметь некоторые макеты и заглушки. См. Эту статью о различии между ними. Короче говоря (AFAIK), заглушка - всего лишь объект эмуляции, который всегда работает. И макет (который должен быть уникальным в каждом тесте) - это элемент, который может изменить результат теста (пройти или сбой).

Для конкретной цели FTP-подключения вы можете, например, (при тестировании на стороне клиента) иметь некоторые заглушки, которые возвращают список файлов, и макет, который будет проверять несколько возможных проблем FTP-сервера (время ожидания, потеря связи, неправильные содержание). Тогда ваша клиентская сторона будет реагировать так, как ожидалось. Ваш макет может быть настоящим экземпляром FTP-сервера, но который будет вести себя так, как ожидается, чтобы вызвать все возможные ошибки. Как правило, каждая ошибка должна вызывать исключение, которое должно отслеживаться тестовыми модулями, чтобы пройти / пропустить каждый тест.

Это немного сложно написать хороший тестовый код. Метод, основанный на проверке, сначала занимает немного времени, но всегда лучше в долгосрочной перспективе. Хорошая книга здесь обязательна или, по крайней мере, некоторые справочные статьи (например, Мартин Фаулер, как указано выше). В Delphi использование интерфейсов и принципов SOLID может помочь вам написать такой код и создать заглушки / макеты для написания ваших тестов.

Из моего эксперимента каждый программист иногда может быть потерян при написании тестов ... хорошая запись теста может быть более трудоемкой, чем запись функций, в некоторых случаях ... вы предупреждаетесь! Каждый тест должен рассматриваться как признак, и его стоимость должна оцениваться: стоит ли это? Не подходит ли еще один тест здесь? Является ли мой тест отключенным от функции, которую он тестирует? Это еще не проверено? Я проверяю свой код или стороннюю / библиотечную функцию?

Из темы, но мои два цента: HTTP / 1.1 может быть лучшим кандидатом в настоящее время, чем FTP, даже для обновления файлов. Вы можете возобновить HTTP-соединение, загружать контент HTTP кусками параллельно, и этот протокол более прокси-сервер, чем FTP. И гораздо проще разместить некоторый HTTP-контент, чем FTP (на некоторых FTP-серверах также известны проблемы с безопасностью). Большинство обновлений программного обеспечения в настоящее время выполняются через HTTP / 1.1, а не FTP (например, продукты Microsoft или большинство репозиториев Linux).

РЕДАКТИРОВАТЬ:

Вы можете утверждать, что вы проводите интеграционные тесты, когда используете удаленный протокол. Это может иметь смысл, но ИМХО это не одно и то же.

Насколько я понимаю, интеграционные тесты проводятся, когда вы позволяете всем вашим компонентам работать вместе с реальным приложением, а затем проверяйте, что они работают должным образом. Мое предложение о тестировании FTP заключается в том, что вы издеваетесь над FTP-сервером, чтобы явно протестировать все возможные проблемы (время ожидания, соединение или ошибка передачи ...). Это не что иное, как интеграционные тесты: покрытие кода намного больше. И вы проверяете только часть кода, а не всю интеграцию кода. Это связано не только с тем, что вы используете какое-то удаленное соединение, которое вы делаете с интеграционными тестами: это все равно унитарное тестирование.

И, конечно же, интеграционные и системные испытания должны проводиться после унитарных испытаний. Но унифицированные тесты FTP-клиента могут издеваться над FTP-сервером, запускать его локально, но тестировать все возможные проблемы, которые могут возникнуть в реальной большой глобальной сети.


Answer #3

Если вы используете компонент TIdFTP Indy 10, то вы можете использовать класс TIdIOHandlerStream Indy для подделки FTP-соединения без фактического физического подключения к реальному FTP-серверу.

Создайте объект TStream , такой как TMemoryStream или TStringStream , который содержит ответы FTP, которые вы ожидаете получить TIdFTP для всех команд, которые он отправляет (используйте сниффер пакетов, чтобы заранее зафиксировать их, чтобы дать вам представление о том, что вам нужно включить) и поместите копию файла обновления в локальную папку, куда вы обычно загружаете. Создайте объект TIdIOHandlerStream и назначьте TStream качестве ReceiveStream , затем назначьте этот IOHandler TIdFTP.IOHandler перед вызовом Connect() .

Например:

ResponseData := TStringStream.Create(
  '220 Welcome' + EOL +
  ... + // login responses here, etc...
  '150 Opening BINARY mode data connection for filename.ext' + EOL +
  '226 Transfer finished' + EOL +
  '221 Goodbye' + EOL);

IO := TIdIOHandlerStream.Create(FTP, ResponseData); // TIdIOHandlerStream takes ownership of ResponseData by default

FTP.IOHandler := IO;
FTP.Passive := False;  // Passive=True does not work under this setup

FTP.Connect;
try
  FTP.Get('filename.ext', 'c:\path\filename.ext');
  // copy your test update file to 'c:\path\filename.ext'...
finally
  FTP.Disconnect;
end;




delphi-2010