Подтвердить что ты не робот

Почему я должен и Unit test И веб-тест (а не только веб-тест)?

Моя текущая позиция такова: если я тщательно тестирую свои приложения ASP.NET с помощью веб-тестов (в моем случае с помощью инструментов тестирования VS.NET'08 и WatiN, возможно) с охватом кода и широким спектром данных, я не нужно будет писать отдельные модульные тесты, потому что мой код будет протестирован в сочетании с пользовательским интерфейсом через все слои. Покрытие кода гарантирует, что я нажму каждый функциональный фрагмент кода (или покажу неиспользованный код), и я могу предоставить данные, которые будут охватывать все разумно ожидаемые условия.

Однако, если у вас другое мнение, я хотел бы знать:

  • Какое дополнительное преимущество дает модульное тестирование, которое оправдывает усилия по включению его в проект (имейте в виду, что я делаю веб-тесты в любом случае, поэтому во многих случаях модульные тесты будут охватывать код, который веб-тесты уже охватывают).

  • Можете ли вы подробно объяснить свои причины примерами concete? Слишком часто я вижу ответы типа "это не то, что это означает", или "это способствует повышению качества", что действительно не затрагивает практический вопрос, с которым мне приходится сталкиваться, а именно, как я могу оправдать - с ощутимыми результатами - тратить больше время тестирования?

4b9b3361

Ответ 1

Покрытие кода гарантирует, что я нажму каждый функциональный фрагмент кода

"Хит" не означает "Тестирование"

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

Просто потому, что вы загрузили страницу, и она не сработала, это не значит, что она действительно работает правильно. Вот некоторые вещи, с которыми я столкнулся, когда "веб-тесты" покрывали 100% кода, но полностью упустили некоторые очень серьезные ошибки, которые не выполнялись бы при тестировании модулей.

  • Страница загружена правильно из кеша, но фактическая база данных была нарушена
  • Страница загружала каждый элемент из базы данных, но отображала только первую: оказалось, что она прекрасна, даже если она полностью не работает, потому что она слишком долгое время
  • На странице отображается действительный номер, который был действительно неправильным, но он не был поднят, потому что 1000000 легко ошибиться для 100000
  • На странице отображается действительное число по совпадению - 10x50 совпадает с 25x20, но один из них WRONG
  • Предполагалось, что страница должна добавить запись в базу данных, но это не видно пользователю, чтобы ее не видели.
  • Аутентификация была обойдена, чтобы веб-тесты действительно работали, поэтому мы пропустили вопиющую ошибку в коде аутентификации.

Легко придумать сотни примеров таких вещей.

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

Ответ 2

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

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

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

Ответ 3

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

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

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

Приемочные испытания проверяют систему так же, как вы ее доставляете - от GUI к базе данных. Иногда они берут часы или дни (или недели) для запуска.

Если вы начнете думать о нем как о двух совершенно разных зверях, вы будете гораздо более эффективным тестером.

Ответ 4

Хорошие, ориентированные unittests значительно ускоряют поиск и устранение проблем, когда они возникают. Когда хорошо написанный unittest ломается, вы знаете, что такое отказ и что вызвало его.

Кроме того, они, как правило, быстрее запускаются, что означает, что вы гораздо чаще запускаете их во время разработки как часть цикла редактирования-компиляции (в отличие от того, когда вы собираетесь зарегистрироваться).

Ответ 5

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

Если вы пишете модульные тесты в стиле TDD, вы, вероятно, не будете делать столько ненужного кода, потому что сосредоточитесь на крошечных шагах и делаете только необходимые.

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

И сами unit test будут служить в качестве экстренной документации о том, что система делает и не делает.

Это всего лишь несколько примеров преимуществ, которые я заметил при применении TDD к моей работе.

Ответ 6

Еще один аспект - простить несколько идеальную среду, в которой он находится:

Предположим, у вас есть 3 компонента, которые, наконец, должны работать вместе. Каждый из них может быть полностью протестирован на единицу (независимо от того, что это означает) с 5 модульными тестами. Это делает 5 + 5 + 5 = 15 единичными тестами для полного покрытия.

Теперь, если у вас есть ваш интеграционный/веб-/комбинированный тест, который проверяет все компоненты вместе, вам понадобится (помните идеальный мир для этого абстрактного сценария) 5 * 5 * 5 = 125. проверьте все перестановки, чтобы дать вам тот же результат, что и 15 тестовых примеров выше (учитывая, что вы даже можете инициировать все перестановки, иначе было бы непроверенное/неуказанное поведение, которое может укусить вас позже при расширении ваших компонентов).

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

Ответ 7

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

Например, если у вас был веб-тест, он отправил запрос Ajax обратно на службу на сервере, которая затем попала в базу данных, а затем не удалась. Это вызвало проблему Javascript, службу, бизнес-логику или базу данных?

Где, как если бы вы unit test каждый из своих услуг самостоятельно, заглушая/избивая базу данных или каждый блок бизнес-логики, тогда вы с большей вероятностью узнаете, где именно ошибка. Единичное тестирование меньше касается охвата (хотя и важного) и более об изоляции.

Ответ 8

Практически, как сказал Дийкстра: модульные тесты могут быть использованы только для того, чтобы показать, что у программного обеспечения есть дефекты, а не для того, чтобы доказать, что он без дефектов. Таким образом, в общем случае попадание в каждый путь кода один раз (и получение 100% покрытия) не имеет никакого отношения к тестированию - это просто помогает устранить битрот.

Если вы играете в книгу, каждая серьезная ошибка должна быть устранена только после того, как будет написано unit test, которое вызывает эту ошибку. Кстати, исправление ошибки означает, что этот конкретный unit тест больше не терпит неудачу. В будущем этот unit test проверяет, что эта ошибка остается фиксированной.

Намного проще написать unit test, который вызывает определенную ошибку, чем писать сквозной (веб-тест), который делает ТОЛЬКО это и не запускает кучи совершенно ненужного кода на этом пути (что могло бы также терпят неудачу и запутываются с анализом основных причин).

Ответ 9

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

Интеграционные тесты (или "веб-тесты" в этом случае) также очень важны, но являются более поздней строкой защиты, чем модульные тесты. Один интеграционный тест охватывает такой огромный пробел кода, который, когда он не выполняется, требует большого количества исследований, чтобы определить дефект (или, возможно, группу дефектов), который вызвал отказ. Это дорого, особенно когда вы пытаетесь протестировать сборку релизов, чтобы вытащить ее из двери. Это еще более дорого, учитывая, что вероятность введения ошибки с исправлением в среднем имеет довольно высокий уровень и вероятность того, что отказ блокирует дальнейшее тестирование выпуска (что чрезвычайно дорого для цикла разработки).

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

Всегда лучше исправлять ошибки позже, чем раньше. Всегда.

Подумайте о строительстве автомобиля. Не могли бы вы подождать, пока все транспортное средство откатится от сборочной линии, чтобы проверить, что каждый компонент работает? В этот момент, если вы обнаружите, что проигрыватель компакт-дисков или движок или кондиционер или круиз-контроль не работают, вам необходимо снять весь автомобиль с линии, устранить проблему, а затем повторно проверить все (что, надеюсь, не выявить любые новые дефекты). Очевидно, это неправильный способ сделать это, так как очевидно, что неправильно пытаться выпускать программное обеспечение, а только тестировать, если оно работает в конце процесса, а не на каждом важном шаге вдоль линии с нуля.

Ответ 10

Это зависит от архитектуры приложения ASP.NET. Если веб-страницы просто подключают базовый уровень бизнес-логики или уровень доступа к данным, то тесты модулей, работающие независимо от модели состояния ASP.NET, быстрее разрабатываются и запускаются, чем аналогичные тесты WaitiN.

Недавно я разработал область унаследованного приложения ASP.NET в Visual Studio 2003 с NUnit в качестве тестовой среды. В то время как ранее тестирование включало работу с помощью тестов пользовательского интерфейса, чтобы гарантировать, что функциональность была реализована правильно, 90% тестирования произошло без необходимости взаимодействия с пользовательским интерфейсом.

Единственная проблема, с которой я столкнулся, - это временные оценки - одна из задач была запланирована в Trac как 1 день для доступа к данным/бизнес-логики и 2 дня для создания и тестирования пользовательского интерфейса. Когда NUnit работает над логикой доступа к данным/бизнес-логикой, время для этой части разработки прошло от 1 дня до 2 дней. Развитие пользовательского интерфейса сократилось до одного дня.

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

Ответ 11

Единичное тестирование позволяет проводить более строгие тесты производительности и упрощает определение того, где возникают узкие места. Для больших приложений производительность становится серьезной проблемой, когда 10 000 пользователей одновременно используют метод, если этот метод занимает 1/100-ю секунду для выполнения, возможно, из-за плохо написанного запроса к базе данных, поскольку теперь некоторые из пользователей должны подождите, пока страница не загрузится до 10 секунд. Я знаю, что лично я не буду долго ждать загрузки страниц и просто перейду в другое место.

Ответ 12

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

Другими словами, потенциальные точки отказа лучше изолируются к моменту начала вашего приемочного тестирования, потому что вы уже проработали потенциальные ошибки в своем коде с помощью модульных тестов. С историей модульных тестов вы узнаете, что только определенные модули будут вызывать определенные ошибки. Это значительно упрощает отслеживание кода преступника.