Я недавно закончила колледж и начинаю учиться где-то на следующей неделе. Мы видели модульные тесты, но мы их мало использовали; и все говорят о них, так что я подумал, может быть, я должен сделать что-нибудь.
Проблема в том, что я не знаю, что тестировать. Должен ли я проверить общий случай? Крайний случай? Как я знаю, что функция адекватно покрыта?
У меня всегда возникает ужасное ощущение, что хотя тест докажет, что функция работает для определенного случая, абсолютно бесполезно доказывать, что функция работает, точка.
Ответы:
Моя личная философия, таким образом, была:
источник
Таким образом, среди множества ответов никто не затронул разделение эквивалентности и анализ граничных значений , жизненно важные соображения в ответе на данный вопрос. Все остальные ответы, хотя и полезны, являются качественными, но возможно - и предпочтительнее - быть здесь количественными. @fishtoaster предоставляет некоторые конкретные рекомендации, просто заглядывая под покровы тестовой количественной оценки, но разделение по эквивалентности и анализ граничных значений позволяют нам работать лучше.
При разделении по эквивалентности вы делите набор всех возможных входных данных на группы на основе ожидаемых результатов. Любой вклад из одной группы даст эквивалентные результаты, поэтому такие группы называются классами эквивалентности . (Обратите внимание, что эквивалентные результаты не означают идентичные результаты.)
В качестве простого примера рассмотрим программу, которая должна преобразовывать символы ASCII в нижнем регистре в символы верхнего регистра. Другие персонажи должны претерпеть преобразование личности, то есть остаться без изменений. Вот одно из возможных разбиений на классы эквивалентности:
В последнем столбце указано количество тестов, если вы перечислите все из них. Технически, по правилу 1 @ fishtoaster вы бы включили 52 тестовых случая - все из них для первых двух строк, приведенных выше, подпадают под «общий случай». Правило 2 @ fishtoaster также добавит некоторые или все строки 3 и 4 выше. Но при тестировании с разделением эквивалентности достаточно одного теста в каждом классе эквивалентности. Если вы выберете «a», «g» или «w», вы тестируете тот же путь кода. Таким образом, у вас есть 4 тестовых случая вместо 52+.
Анализ граничных значений рекомендует небольшое уточнение: по сути, он предполагает, что не каждый член класса эквивалентности, ну, в общем, эквивалентен. То есть значения на границах также должны рассматриваться как достойные тестового примера сами по себе. (Одно простое оправдание этому - печально известная ошибка «один на один» !) Таким образом, для каждого класса эквивалентности вы можете иметь 3 входных сигнала теста. Глядя на входную область выше - и с некоторыми знаниями о значениях ASCII - я мог бы придумать эти входные данные тестового примера:
(Как только вы получите более 3 граничных значений, которые предполагают, что вы, возможно, захотите переосмыслить свои исходные разграничения классов эквивалентности, но это было достаточно просто, и я не стал возвращаться к их пересмотру.) Таким образом, анализ граничных значений подводит нас к 17 тестовых случаев - с высокой степенью достоверности полного охвата - по сравнению со 128 тестовыми случаями для проведения исчерпывающего тестирования. (Не говоря уже о том, что комбинаторика диктует, что исчерпывающее тестирование просто невозможно для любого реального приложения!)
источник
Наверное, мое мнение не слишком популярно. Но я предлагаю вам быть экономным с юнит-тестами. Если у вас слишком много модульных тестов, вы легко можете потратить половину своего времени или больше на поддержание тестов, а не на фактическое кодирование.
Я предлагаю вам написать тесты на вещи, которые у вас плохое предчувствие, или вещи, которые очень важны и / или элементарны. Модульные тесты IMHO не являются заменой для хорошего инженерного и защитного кодирования. В настоящее время я работаю над проектом, который более или менее непригоден. Это действительно стабильно, но боль от рефакторинга. Фактически никто не трогал этот код за один год, а программному стеку, на котором он основан, 4 года. Почему? Потому что он перегружен юнит-тестами, а точнее: юнит-тестами и автоматизированными интеграционными тестами. (Вы когда-нибудь слышали о огурце и тому подобном?) И вот лучшая часть: этот (пока) неиспользуемый кусок программного обеспечения был разработан компанией, сотрудники которой являются первопроходцами на сцене разработки, управляемой тестами. : D
Итак, мое предложение:
Начните писать тесты после того, как вы разработали базовый скелет, иначе рефакторинг может быть болезненным. Как разработчик, который разрабатывает для других, вы никогда не получите требования с самого начала.
Убедитесь, что ваши юнит-тесты могут быть выполнены быстро. Если у вас есть интеграционные тесты (например, огурец), то все в порядке, если они занимают немного больше времени. Но длительные тесты не доставляют удовольствия, поверьте мне. (Люди забывают все причины, почему C ++ стал менее популярным ...)
Оставьте этот материал TDD экспертам TDD.
И да, иногда вы концентрируетесь на крайних случаях, иногда на общих случаях, в зависимости от того, где вы ожидаете неожиданного. Хотя, если вы всегда ожидаете неожиданного, вам следует по-настоящему пересмотреть свой рабочий процесс и дисциплину. ;-)
источник
Leave this TDD stuff to the TDD-experts
.Если вы сначала тестируете с помощью Test Driven Development, то ваш охват увеличится до 90% или выше, потому что вы не добавите функциональность, не написав сначала провальный модульный тест для нее.
Если вы добавляете тесты после факта, то я не могу порекомендовать вам достаточно, чтобы вы получили копию Майкла Фезерса « Эффективная работа с унаследованным кодом » и ознакомились с некоторыми методами добавления тестов в код и способами рефакторинга кода. чтобы сделать его более тестируемым.
источник
The problem is, I don't know _what_ to test
Если начать следующий Test Driven развития практики, они будут своего рода руководство вас через процесс и зная , что тестирование будет, естественно. Некоторые места для начала:
Тесты на первом месте
Никогда, никогда не пишите код перед написанием тестов. Смотрите Red-Green-Refactor-Repeat для объяснения.
Написать регрессионные тесты
Всякий раз, когда вы сталкиваетесь с ошибкой, напишите тестовый пример и убедитесь, что он не работает . Если вы не можете воспроизвести ошибку через неудачный тестовый сценарий, вы на самом деле ее не нашли.
Красно-зеленый-Refactor-Repeat
Красный : начните с написания самого простого теста поведения, которое вы пытаетесь реализовать. Думайте об этом шаге как о написании некоторого примера кода, который использует класс или функцию, над которой вы работаете. Убедитесь, что он компилируется / не имеет синтаксических ошибок и что он не работает . Это должно быть очевидно: вы не написали ни одного кода, поэтому он должен потерпеть неудачу, верно? Здесь важно учиться тому, что, если вы не увидите, что тест провалился хотя бы один раз, вы никогда не сможете быть уверены, что если он пройдет, он сделает это из-за чего-то, что вы сделали по какой-то фиктивной причине.
Зеленый : написать самый простой и глупый код, который на самом деле проходит тест. Не пытайся быть умным. Даже если вы видите, что есть очевидный крайний случай, но тест учитывает, не пишите код для его обработки (но не забывайте о крайнем случае: он понадобится вам позже). Идея состоит в том, что каждый кусок кода, который вы пишете, каждый
if
, каждый,try: ... except: ...
должен быть подтвержден тестовым примером. Код не должен быть элегантным, быстрым или оптимизированным. Вы просто хотите пройти тест.Рефакторинг : Очистите ваш код, получите правильные имена методов. Посмотрите, проходит ли тест еще раз. Оптимизация. Запустите тест снова.
Повторяю : вы помните крайний случай, который тест не охватывал, верно? Итак, теперь это его важный момент. Напишите тестовый сценарий, который охватывает эту ситуацию, посмотрите, как он провалится, напишите некоторый код, посмотрите, как он прошел, рефакторинг.
Проверьте свой код
Вы работаете над определенным фрагментом кода, и это именно то, что вы хотите проверить. Это означает, что вы не должны тестировать библиотечные функции, стандартную библиотеку или ваш компилятор. Также постарайтесь не испытывать «мир». Это включает в себя: вызов внешних веб-API, некоторые вещи с интенсивным использованием базы данных и т. Д. Всякий раз, когда вы можете попытаться смоделировать его (создайте объект, который следует тому же интерфейсу, но возвращает статические, предопределенные данные).
источник
Для модульных тестов начните с тестирования того, что он делает то, для чего он предназначен. Это должен быть самый первый случай, когда ты пишешь. Если частью дизайна является «оно должно вызвать исключение, если вы проходите в мусор», проверьте это тоже, так как это является частью дизайна.
Начни с этого. По мере того, как вы приобретете опыт выполнения этого базового тестирования, вы начнете узнавать, достаточно ли этого или нет, и начнете видеть другие аспекты вашего кода, требующие тестирования.
источник
Основной ответ - «проверить все, что может сломаться» .
Что слишком просто сломать? Поля данных, средства доступа к объектам, находящимся в тупике, и аналогичные дополнительные данные. Все остальное, вероятно, реализует некоторую идентифицируемую часть требования и может выиграть от тестирования.
Конечно, ваш пробег - и ваши рабочие условия - могут отличаться.
источник