Как вы юнит тест? - PullRequest
       75

Как вы юнит тест?

8 голосов
/ 28 ноября 2008

Я прочитал немного о модульном тестировании и мне было интересно, как ВЫ тестируете модульное тестирование. Очевидно, что модульное тестирование должно разбивать программу на очень маленькие «единицы» и тестировать функциональность оттуда.

Но мне интересно, достаточно ли этого для юнит-тестирования класса? Или вы берете это еще дальше и юнит-алгоритмы, формулы и т. Д.? Или вы расширяете его для модульного тестирования ASP-страниц / функциональности? Или ты вообще юнит тест?

Ответы [ 9 ]

5 голосов
/ 28 ноября 2008

Я использую модульные тесты в качестве инструмента для измерения того, работает ли что-то по-прежнему, после того, как я внес некоторые изменения в код (например, рефакторинг, исправление ошибки, добавление расширения). Поскольку я использую Java, модульные тесты в значительной степени автоматизированы с помощью JUnit. Просто вызовите один сценарий командной строки и запустите сотни тестов, чтобы убедиться, что код не нарушен.

5 голосов
/ 28 ноября 2008

Но мне интересно, достаточно ли этого для модульного тестирования класса? Или вы берете это еще дальше и юнит-алгоритмы, формулы и т. Д.? Или вы расширяете его для модульного тестирования ASP-страниц / функциональности? Или ты вообще юнит тест?

Алгоритм должен быть в классе и автоматически должен проверяться модулем. Формула находится внутри класса как функция, и они также проверяются на unit . Модульное тестирование тестирует поведение, состояние и все, что может быть протестировано для самой маленькой единицы разработки. Так что да, алгоритм проверен со всеми деталями. Позже, когда у вас есть классы, которые используют другой класс, вы будете выполнять интеграционные тесты (они часто тестируются с помощью программ Unit Test). Это будет то же самое, но на более высоком уровне.

2 голосов
/ 28 ноября 2008

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

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

assert(os.quote [[three]] == [[three]])
assert(os.quote [[three"]] == [['three"']])
assert(os.quote [[your mama]] == [['your mama']])
assert(os.quote [[$i]] == [['$i']])

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

Другая вещь, которую я делаю с модульным тестированием, заключается в том, что если это что-то сложное, я проверяю алгебраические законы , используя QuickCheck , который представляет собой инструмент случайного тестирования, который нужно уверовал. Это единственный инструмент, который я когда-либо использовал, который делает юнит-тестирование веселым . Ссылка там свисает, но вы можете найти историю Тома Мёртеля о конкурсе программ ICFP в его блоге.

Надеюсь, вы найдете это полезным. QuickCheck спас мой бекон много раз. Совсем недавно я протестировал код для дискретного косинусного преобразования, используя точную рациональную арифметику, а затем перенес его на C!

2 голосов
/ 28 ноября 2008

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

1) Определение пограничных объектов (Win / WebForms, CustomControls и т. Д.).

2) Идентифицировать объекты управления (объекты бизнес-уровня)

3) Обязательно напишите модульные тесты как минимум для открытых объектов управления. Методы, вызываемые граничными объектами.

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

2 голосов
/ 28 ноября 2008

i unit test содержит , а не отдельные методы или классы. Затраты на написание и поддержку модульных тестов не являются незначительными, и в целом я не рекомендую писать модульные тесты для каждого небольшого кусочка кода. Однако возможности модульного тестирования стоят того, потому что клиент платит за них.

1 голос
/ 28 ноября 2008

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

Давайте посмотрим правде в глаза: если вы перенесете матричное преобразование из matlab, легко испортить где-нибудь знак плюс или минус. Подобные вещи трудно увидеть. Не пробуя это, вы просто не знаете, будет ли это работать правильно. Отладка 100 строк кода намного проще, чем отладка 100 000 строк кода.


Некоторые люди доводят это до крайности. Они пытаются проверить все мыслимые вещи. Испытание становится самоцелью.

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

Но накладные расходы могут нанести ущерб разработке продукта! А будущие изменения, которые изменят функциональность, могут повлечь за собой значительные накладные расходы на обновление тестов.

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


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

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

Например: когда я писал код для отправки / получения сообщений по UDP, я собрал быстрый тест для отправки / получения данных с использованием этого класса через интерфейс обратной связи. Ничего фантастического. Быстрый, быстрый и грязный код. Я просто хотел попробовать это. Чтобы убедиться, что он действительно работал, прежде чем я что-то построил поверх него.

Другой пример: чтение изображений с камеры Firewire. Я собрал быстрое и грязное приложение GTK, чтобы читать изображения, обрабатывать их и отображать в реальном времени. Другие называют это интеграционным тестированием. Но я могу использовать его, чтобы проверить мой интерфейс Firewire, мой класс Image, мое преобразование Bayer RGGB-> RGB, мою ориентацию и выравнивание изображения, даже если камера была снова установлена ​​вверх ногами. Более подробное тестирование было бы оправданным только в том случае, если этого оказалось недостаточно.

С другой стороны, даже для чего-то простого:

template<class TYPE> inline TYPE MIN(const TYPE & x, const TYPE & y) { return x > y ? y : x; }
template<class TYPE> inline TYPE MAX(const TYPE & x, const TYPE & y) { return x < y ? y : x; }

Я написал 1-строчный макрос SHOW, чтобы убедиться, что я не испортил знак:

  SHOW(MIN(3,4));  SHOW(MAX(3,4));

Все, что я хотел сделать, это убедиться, что он делает то, что должен делать в общем случае. Я меньше беспокоюсь о том, как он обрабатывает NaN / + -Infinity / (double, int), чем о том, решил ли один из коллег изменить порядок аргументов и обманывают.


С точки зрения инструментов, есть много вещей для юнит-тестирования. Если это поможет вам, больше сил для вас. Если нет, то на самом деле вам не нужно слишком увлекаться.

Я часто пишу тестовую программу, которая выводит данные в класс и из класса, а затем распечатывает все это с помощью макроса SHOW:

#define SHOW(X)  std::cout << # X " = " << (X) << std::endl

(В качестве альтернативы, многие из моих классов могут печатать самостоятельно, используя встроенный метод operator << (ostream &). Это удивительно полезный метод для отладки и тестирования!) </p>

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

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


Последняя мысль, которую я оставлю тебе. Это пометит меня, поэтому НЕ сделай это!

Некоторое время назад мне понадобилась программа тестирования. Это был обязательный результат. Сама программа должна была проверить, что другой класс работал правильно. Но он не мог получить доступ к внешним файлам данных. (Мы не могли полагаться на то, где будет располагаться программа относительно чего-либо еще. Абсолютных путей тоже не было.) Среда модульного тестирования для проекта была несовместима с компилятором, который мне нужно было использовать. Это также должно было быть в одном файле. Система makefile проекта не поддерживает связывание нескольких файлов для простой тестовой программы. (Прикладные программы, конечно. Они могут использовать библиотеки. Но только один файл для каждой тестовой программы.)

Так, Боже, прости меня, я "нарушил правила" ...


Я использовал макросы. Когда был установлен макрос #define, данные записывались во второй файл .c в качестве инициализатора для массива struct. Впоследствии, когда программное обеспечение было перекомпилировано, и этот второй файл .c (с массивом struct) был #included и макрос #define не был установлен, он сравнил новые результаты с ранее сохраненными данными. Да, я включил файл .c. О 'смущение всего этого.

Но это можно сделать ...

1 голос
/ 28 ноября 2008

Недостаточно просто провести модульное тестирование класса. Классы работают вместе, и это тоже нужно проверить.

Есть больше единиц, чем просто классы:

  • модулей,
  • слоев,
  • рамки.

И, конечно, существуют разные формы тестирования, например, интеграция и принятие.

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

1 голос
/ 28 ноября 2008

Я тестирую как можно больше общедоступного интерфейса (я использую C ++, но язык не имеет большого значения). Наиболее важным аспектом является написание тестов, когда вы пишете код (непосредственно перед или после). По опыту уверяю вас, что разработка таким способом приведет к созданию более надежного кода. и облегчит обслуживание (так как изменения, которые прерывают тесты, будут, очевидно, незамедлительными).

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

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

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

1 голос
/ 28 ноября 2008

Мы обычно программируем в библиотеках Java для машин. Программа обычно состоит из более чем двадцати библиотек, поэтому мы проводим модульное тестирование каждой библиотеки. Это непростая задача, так как библиотеки очень часто связаны друг с другом, и это не часто возможно.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...