Статьи

Я не знаю как это проверить


Существует высказывание
Миско Хевери, которое я разделяю (и, вероятно, неправильно цитирую) здесь:


Единственным приемлемым оправданием отсутствия тестов является то, что вы не знаете, как тестировать: тестирование — это способность, которой нужно научиться.

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

  • не распространяйте новые операторы в своей кодовой базе, но попросите, чтобы ваши зависимости были введены через сеттеры или конструкторы (Dependency Injection).
  • Избегайте статических классов и синглетонов , которые поддерживают глобальное состояние и приводят к появлению антипаттернов «действие на расстоянии».
  • Следуйте закону Деметры вместо того, чтобы ходить по всему графу объектов в радиусе 2 километров.

Но как насчет технологий? (Веб-приложение) создается не только объектами в памяти. Он состоит из баз данных, веб-сервисов, движущихся частей, полностью написанных на разных языках, таких как JavaScript …

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

Библиотеки

Гася и насмешливо , и любой другой тест двойной специализации, ваши лучшие друзья , когда речь заходит использовать внешнюю библиотеку. Также полезно создать объект Facade (или несколько объектов) над библиотекой, чтобы следовать принципу «Только макеты», которые у вас есть.

В любом случае, мы говорим о тестировании вашего кода в основном изолированно от библиотеки и нацелены на интеграцию с ним в несколько более медленных и шумных тестов.

Каркасы

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

Humble Object шаблон является безошибочным решением для решения этой проблемы: она состоит в преобразовании рамочных связанных классов в чистых компонентах делегации, оставляя всю логику для тестирования в отдельном пакете , который вы можете подделать свободу дизайна.

Объектно-реляционное отображение

ORM, взаимодействующий с базой данных, является специализацией случая библиотеки, настолько распространенной специализацией, что у нее есть имя: Data Mapper pattern . ORM, реализованный как Data Mapper, позволяет вам свободно работать с объектами в памяти и передавать их для сохранения в конце пользовательского запроса. Шлюз к базе данных обычно реализуется с помощью шаблона Repository.

CouchApps

Couchapps — это приложения на основе JavaScript, которые обращаются к CouchDB напрямую из браузера (и обслуживаются также через HTTP из экземпляра CouchDB).
Здесь необходимо протестировать два основных компонента:

  • представления экземпляра CouchDB, которые являются просто функциями JavaScript: мы можем проверить их, передав поддельные данные. Например, вы можете использовать комбинацию Rhino и Qunit или jsTestDriver (это мой предпочтительный выбор), чтобы протестировать их независимо. Я бы предпочел использовать SpiderMonkey, поскольку это то, что использует CouchDB, но я до сих пор не знаю, возможно ли это или достаточно просто запустить в нем инфраструктуру тестирования.
  • Часть браузера, которая использует Ajax и DOM. Смотрите соответствующую мини-главу этой статьи.

Работа с графикой

Функциональное и сквозное тестирование требует указания всех входных данных. В случае веб-тестирования — полный запрос и ответ; в случае графических тестов — гигантские матрицы пикселей.

Вот почему при работе с графическими данными, такими как изображения или видеокадры, я использую упрощенные версии этих объектов в тестах. Если я хочу протестировать графические преобразования, которые просто поворачивают изображение на 90 °, я могу использовать изображение размером 2×3 пикселя, созданное в памяти. И если я смогу тестировать ротацию и перевод отдельно в одном классе, я буду уверен, что в большинстве случаев они будут работать вместе.

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

Без xUnit

Если для вашего языка (реже и реже) отсутствует платформа xUnit, вам придется самостоятельно создавать простую версию такого инструмента. Если phpt выполняет работу для всего мира нативных функций PHP, на самом деле не сложно создать среду тестирования.

Для того, чтобы это было легко, важно быть на языке ОО. В Matlab есть квазиофициальный фреймворк xUnit , но работающий над функциями и вложенными функциями вместо объектов. Нет ничего, что могло бы исправить отсутствие объектной ориентации языка, но многие практики, такие как абсолютное устранение дублирования , будут работать на каждом языке, полном по Тьюрингу.

Ajax-интенсивные приложения

Год назад я бы выкрикнул Selenium , известный инструмент для комплексного тестирования веб-приложений, которые управляют браузерами, нажимая и утверждая отображаемый текст и события. Но тесты Selenium очень хрупкие и подходят только для сквозных тестов, а не, например, для тестирования нашего кода JavaScript.

Модульное тестирование JavaScript всегда существовало (см., Например, JsUnit и его эволюцию Jasmine ), но теперь это намного проще с Google jsTestDriver, который захватывает браузеры и может быть запущен из командной строки.

Таким образом, проблема больше не в инструменте: даже если не учитывать jsTestDriver, в Интернете доступно множество фреймворков. Проблема заключается в изоляции от глобального состояния браузера, такого как элементы DOM или создание XmlHttpRequests, но это проблема дизайна, с которой я сталкиваюсь.

JavaScript позволяет очень быстро создавать заглушки, поскольку он поддерживает замену функций на лету:

oldAjax = jQuery.ajax;
jQuery.ajax = function () {}
// execute your test...
jQuery.ajax = oldAjax;

Но состав объектов и функций возможен и предпочтителен, как и в любом другом языке ОО.

Это только примеры

Это много примеров, и я надеюсь, что некоторые из них будут вам полезны. Но сегодня я надеюсь, что придерживаюсь следующего: когда вы избегаете написания теста, потребуйте себя, если это так, потому что вы действительно не знаете как. Миско хорошо справился с проблемами проектирования ОО, но, как веб-разработчики, мы используем много видов технологий и языков: наши навыки тестирования должны быть уточнены и по отношению к ним, поскольку мы не всегда пишем объекты Java (или PHP) в памяти которые объединяют строки, но также и классы JavaScript, которые запускают HTTP-запросы как сумасшедшие.