Я следую TDD религиозно. Мои проекты обычно имеют 85% или лучше тестовое покрытие, со значимыми тестовыми примерами.
Я много работаю с HBase , и основной интерфейс клиента, HTable, очень неприятен. Для написания модульных тестов у меня уходит в 3 или 4 раза больше времени, чем для написания тестов, использующих действующую конечную точку.
Я знаю, что с философской точки зрения тесты, использующие макеты, должны иметь приоритет над тестами, которые используют действующую конечную точку. Но издевательство над HTable - серьезная боль, и я не уверен, что он дает много преимуществ по сравнению с тестированием на живом экземпляре HBase.
Каждый в моей команде запускает экземпляр HBase с одним узлом на своей рабочей станции, и у нас есть экземпляры HBase с одним узлом, работающие на наших коробках Jenkins, так что это не проблема доступности. Тесты живых конечных точек, очевидно, занимают больше времени, чем тесты, использующие макеты, но нас это не волнует.
Прямо сейчас я пишу живые тесты конечных точек И тесты на основе макетов для всех моих классов. Я хотел бы отказаться от насмешек, но я не хочу, чтобы в результате качество ухудшалось.
Что вы все думаете?
источник
Ответы:
Моя первая рекомендация - не издеваться над типами, которые вам не принадлежат . Вы упомянули, что HTable - это настоящая боль для насмешек - возможно, вам следует вместо этого обернуть его в адаптер, который предоставляет 20% необходимых вам функций HTable, и при необходимости высмеивать оболочку.
При этом давайте предположим, что мы говорим о типах, которыми вы все владеете. Если ваши фиктивные тесты сосредоточены на сценариях счастливого пути, где все идет гладко, вы ничего не потеряете, потому что ваши интеграционные тесты, вероятно, уже тестируют те же самые пути.
Однако отдельные тесты становятся интересными, когда вы начинаете думать о том, как тестируемая система должна реагировать на каждую мелочь, которая может произойти, как это определено в контракте ее сотрудника, независимо от того, с каким конкретным объектом она разговаривает. Это часть того, что некоторые называют основной правильностью . Таких маленьких кейсов может быть много, а комбинаций гораздо больше. Именно здесь интеграционные тесты начинают становиться паршивыми, в то время как изолированные тесты остаются быстрыми и управляемыми
Чтобы быть более конкретным, что произойдет, если один из методов вашего адаптера HTable возвращает пустой список? Что если он вернет ноль? Что делать, если выдается исключение соединения? В контракте Адаптера должно быть определено, может ли произойти что-либо из этого, и любой из его потребителей должен быть готов справиться с этими ситуациями , следовательно, необходимо провести их тестирование.
Подводя итог: вы не увидите никакого снижения качества, удалив ложные тесты, если они проверяли те же вещи, что и ваши интеграционные тесты . Однако попытка представить дополнительные изолированные тесты (и контрактные тесты ) может помочь вам обдумать ваши интерфейсы / контракты и повысить качество за счет устранения дефектов, о которых было бы сложно думать и / или медленных тестировать с помощью интеграционных тестов.
источник
Я думаю , по крайней мере, это точка нынешнего продолжающегося спора среди TDD сторонников.
Мое личное мнение выходит за рамки того, чтобы сказать, что тест на основе имитации - это в основном способ представления формы интерфейса контракта ; в идеале он ломается (то есть выходит из строя) тогда и только тогда, когда вы меняете интерфейс . И как таковой, в достаточно строго типизированных языках, таких как Java, и при использовании явно определенного интерфейса это почти полностью излишне: компилятор уже сообщит вам, если вы изменили интерфейс.
Основным исключением является случай, когда вы используете очень общий интерфейс, возможно, основанный на аннотациях или отражениях, что компилятор не может автоматически использовать автоматическое отслеживание. Даже в этом случае вы должны проверить, есть ли способ сделать проверку программно (например, библиотеку проверки синтаксиса SQL), а не вручную, используя макеты.
Это тот последний случай, который вы делаете при тестировании с «живой» локальной базой данных; Реализация htable вступает в силу и применяет гораздо более полную проверку контракта interfacve, чем вы когда-либо могли бы написать вручную.
К сожалению, гораздо более распространенным применением имитационного тестирования является тест, который:
Такие тесты, конечно, должны быть удалены на месте.
источник
Сколько дольше выполняется тест на основе конечных точек, чем тест на основе имитации? Если он значительно длиннее, то да, стоит потратить время на написание тестов, чтобы ускорить модульные тесты - потому что вам придется запускать их много, много раз. Если это не значительно дольше, даже если тесты на основе конечных точек не являются «чистыми» модульными тестами, если они хорошо выполняют тестирование модуля, нет никаких оснований быть религиозными в этом отношении.
источник
Я полностью согласен с ответом guillaume31, никогда не издевайтесь над типами, которые вам не принадлежат!
Обычно боль в тесте (издевательство над сложным интерфейсом) отражает проблему в вашем дизайне. Возможно, вам нужна некоторая абстракция между вашей моделью и кодом доступа к данным, например, использование шестиугольной архитектуры и шаблона репозитория. Это наиболее обычный способ решения подобных проблем.
Если вы хотите сделать интеграционный тест для проверки, сделайте интеграционный тест, если вы хотите выполнить модульный тест, потому что вы тестируете свою логику, выполните модульный тест и изолируйте постоянство. Но, выполняя интеграционный тест, потому что вы не знаете, как изолировать свою логику от внешней системы (или потому что изолировать ее от боли) - это большой запах, вы выбираете интеграцию, а не единицу, для ограничения вашего дизайна, а не для реальной необходимости. проверить интеграцию.
Взгляните на эту форму разговора Иана Купера: http://vimeo.com/68375232 , он рассказывает о гексагональной архитектуре и тестировании, он рассказывает о том, когда и что надо издеваться, действительно вдохновенный доклад, который решает многие вопросы, такие как ваш, о реальном TDD ,
источник
TL; DR То, как я это вижу, зависит от того, сколько усилий вы потратите на тесты, и было бы лучше потратить больше на вашу реальную систему.
Длинная версия:
Здесь есть несколько хороших ответов, но я думаю по-другому: тестирование - это экономическая деятельность, которая должна окупаться, и если время, которое вы тратите, не возвращается на разработку и надежность системы (или что-то еще, чего вы хотите добиться тесты) тогда вы можете делать плохие инвестиции; Вы занимаетесь созданием систем, а не написанием тестов. Поэтому сокращение усилий по написанию и сопровождению тестов имеет решающее значение.
Например, некоторые основные значения, которые я получаю из тестов:
Тестирование на работающей конечной точке все еще должно обеспечить это.
Некоторые недостатки при тестировании с живой конечной точкой:
Если бы я находился в такой ситуации, и недостатки, по-видимому, не были проблемой, в то время как насмешка над конечной точкой значительно замедлила мою тестовую запись, я бы проверил живую конечную точку в одно мгновение, если бы был уверен проверьте еще раз через некоторое время, чтобы увидеть, что недостатки не являются проблемой на практике.
источник
С точки зрения тестирования есть некоторые требования, которые абсолютно необходимы:
Это большая проблема при подключении к любому источнику, который поддерживает состояние вне ваших тестов. Это не «чистый» TDD, но команда Ruby on Rails решила эту проблему таким образом, чтобы ее можно было адаптировать для ваших целей. Тестовая структура рельсов работала так:
Вся эта работа была встроена в тестовую оснастку, и она работает достаточно хорошо. Это еще не все, но для этого разговора достаточно основ.
В различных командах, с которыми я работал со временем, мы делали выбор, который способствовал бы тестированию кода даже если это был не самый правильный путь. В идеале мы должны обернуть все вызовы в хранилище данных кодом, который мы контролируем. Теоретически, если какой-либо из этих старых проектов получит новое финансирование, мы можем вернуться и перевести их из базы данных в Hadoop, сосредоточив наше внимание только на нескольких классах.
Важные аспекты - не связываться с производственными данными и убедиться, что вы действительно тестируете то, что, по вашему мнению, тестируете. Очень важно иметь возможность сбрасывать внешний сервис до известного базового уровня по требованию - даже из вашего кода.
источник