Тесты интеграции (базы данных) плохие?

120

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

Я считаю, что в некоторых случаях юнит-тест просто ничего не доказывает.

Давайте возьмем следующую (тривиальную, наивную) реализацию репозитория (в PHP) в качестве примера:

class ProductRepository
{
    private $db;

    public function __construct(ConnectionInterface $db) {
        $this->db = $db;
    }

    public function findByKeyword($keyword) {
        // this might have a query builder, keyword processing, etc. - this is
        // a totally naive example just to illustrate the DB dependency, mkay?

        return $this->db->fetch("SELECT * FROM products p"
            . " WHERE p.name LIKE :keyword", ['keyword' => $keyword]);
    }
}

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

Если не считать интеграционное тестирование с реальным объектом соединения, как я могу знать, что это на самом деле генерирует реальные запросы - и что эти запросы на самом деле делают то, что я думаю, они делают?

Если мне нужно смоделировать объект соединения в модульном тесте, я могу доказать только такие вещи, как «он генерирует ожидаемый запрос» - но это не значит, что он действительно будет работать … то есть, возможно, он генерирует запрос Я ожидал, но, возможно, этот запрос не делает то, что я думаю, что делает.

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

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

Как вы справляетесь с такими ситуациями?

Являются ли интеграционные тесты действительно «плохими» в таком случае?

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

mindplay.dk
источник
5
Прочитайте agitar.com/downloads/TheWayOfTestivus.pdf , особенно стр. 6 «Тест важнее, чем устройство».
Док Браун
2
@ user61852 в описании написано "наивный", да?
mindplay.dk
4
Как ваш коллега был бы абсолютно уверен, что его поддельная база данных ведет себя как настоящая вещь?
Турбьёрн Равн Андерсен
12
Вы пытаетесь быть реалистичным. Ваш коллега пытается придерживаться правил. Всегда пишите тесты, которые производят ценность . Не тратьте время на написание тестов, которые будут несущественными, и не пишите тесты, которые не выполняют одно из следующих действий: увеличьте вероятность того, что ваш код верен, или заставьте вас писать более поддерживаемый код.
jpmc26
3
@ mindplay.dk: ключевое предложение в этом параграфе: «Но не зацикливайтесь на какой-либо догме. Напишите тест, который нужно написать». Кажется, ваш коллега застрял в догме. И вам не нужен кто-то объясняя вам, что такое тест, который должен быть написан в вашем примере - вы уже знаете это. Совершенно очевидно, что для тестирования, если ваша база данных понимает запрос, вы должны выполнить запрос к реальной базе данных - никакая имитация не скажет вам это
Док Браун

Ответы:

129

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

Распространенным способом мышления о тестировании является тестовая пирамида . Эта концепция часто связана с Agile, и многие писали об этом, в том числе Мартин Фаулер (который приписывает ее Майку Кону в « Преуспевании с Agile» ), Алистер Скотт и блог тестирования Google .

        /\                           --------------
       /  \        UI / End-to-End    \          /
      /----\                           \--------/
     /      \     Integration/System    \      /
    /--------\                           \----/
   /          \          Unit             \  /
  --------------                           \/
  Pyramid (good)                   Ice cream cone (bad)

Идея состоит в том, что быстродействующие, гибкие модульные тесты являются основой процесса тестирования - должны быть более сфокусированные модульные тесты, чем системные / интеграционные тесты, и больше системных / интеграционных тестов, чем сквозные тесты. По мере приближения к вершине тесты, как правило, занимают больше времени / ресурсов для выполнения, имеют тенденцию быть более хрупкими и ненадежными и менее конкретны в определении того, какая система или файл повреждены ; естественно, предпочтительнее не быть «тяжелым».

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


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

Джефф Боуман
источник
13
+1 за «Тест, который является идеальным зеркалом своей реализации, на самом деле ничего не тестирует». Все слишком часто. Я называю это Двойным Антипаттерном .
dodgethesteamroller
6
Противоположная школа контроля качества программного обеспечения, контекстно-ориентированное тестирующее движение, частично посвящено обсуждению того, что существуют такие полезные общие правила, как Пирамида тестирования. В частности, основополагающие тексты движения приводят множество примеров, когда интеграционные тесты гораздо более ценны, чем другие виды тестов (потому что они тестируют систему в контексте, как систему ) ....
dodgethesteamroller
7
... следовательно, Фаулер и др., утверждая, что на интеграционные тесты и тесты приемлемости для пользователя следует тратить меньше усилий, поскольку их слишком сложно написать надежным и понятным способом, на самом деле просто дают объяснение ex post facto, почему они не выяснили, как хорошо тестировать на более высоких уровнях.
dodgethesteamroller
1
@dodgethesteamroller Глубокие дискуссии о «противоположной школе», вероятно, лучше всего подходят для их собственного ответа. Лично я нахожу, что блог по тестированию Google довольно неплохо описывает работу быстрых, строго ограниченных автоматических тестов наряду с тестами системы в контексте. Если вам неясно, я перечислю здесь тестовую пирамиду как полезную модель или отправную точку, а не оправдание, чтобы перестать думать как инженер.
Джефф Боуман
1
Настоятельно рекомендуется презентация по иерархии и соотношению юнит-тестов к интеграционным тестам: vimeo.com/80533536 Очень хорошо объяснено.
szalski
88

Один из моих коллег утверждает, что интеграционные тесты - это все виды плохого и неправильного - все должно быть проверено модулем,

Это все равно, что сказать, что антибиотики вредны - все надо лечить витаминами.

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

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

Если не считать интеграционное тестирование с реальным объектом соединения, как я могу знать, что это на самом деле генерирует реальные запросы - и что эти запросы на самом деле делают то, что я думаю, они делают?

Вы можете проверить его на уровне базы данных . Запустите запрос с различными параметрами и посмотрите, получите ли вы ожидаемые результаты. Конечно, это означает копирование / вставку любых изменений обратно в «истинный» код. но это позволит вам проверить независимо запрос любых других зависимостей.

Д Стэнли
источник
Не хотите ли вы проверить, содержит ли база данных определенные данные?
Тулаинс Кордова
Возможно - но вы также можете проверять, работают ли ваши фильтры, сложные объединения и т. Д. Пример запроса, вероятно, не лучший кандидат для «модульных тестов», но может быть и со сложными объединениями и / или объединениями.
Д Стэнли
Да - пример, который я использовал, как указано, тривиален; реальный репозиторий может иметь всевозможные сложные параметры поиска и сортировки, например, с помощью построителя запросов и т. д.
mindplay.dk
2
Хороший ответ, но я бы добавил, что БД должна быть в памяти, чтобы обеспечить быстрое выполнение модульных тестов.
BЈовић
3
@ BЈовић: К сожалению, это не всегда возможно, поскольку, к сожалению, нет двух совместимых БД, и не все они работают в памяти. Существуют также проблемы с лицензированием коммерческих БД (у вас может не быть лицензии на ее запуск на любой машине), ...
Матье М.
17

Модульные тесты не улавливают все дефекты. Но они дешевле в настройке и (повторном) запуске по сравнению с другими видами тестов. Модульные тесты оправданы сочетанием умеренной стоимости и низкой стоимости.

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

введите описание изображения здесь

источник: стр.470 в Коде, Полном 2 Макконнеллом

Ник Алексеев
источник
5
Эти данные были собраны в 1986 году . Это было тридцать лет назад . Модульные испытания в 1986 году были не такими, как сегодня. Я бы скептически отнесся к этим данным. Не говоря уже о том, что модульные тесты обнаруживают ошибки еще до того, как они были совершены , поэтому сомнительно, что о них сообщат.
RubberDuck
3
@RubberDuck Эта диаграмма взята из книги 2006 года и основана на данных 1986, 1996, 2002 годов (если вы внимательно посмотрите). Я не изучал протоколы сбора данных в источниках, я не могу сказать, когда они начали отслеживать дефект и как о нем сообщалось. Может ли этот график быть несколько устаревшим? Это могло бы. В декабре прошлого года я был на семинаре, и инструктор упомянул, что интеграционные тесты обнаруживают больше ошибок, чем модульных (в 2 раза, iirc). Эта диаграмма говорит о том, что они примерно одинаковы.
Ник Алексеев
13

Нет, они не плохие. Надеюсь, у вас должны быть модульные и интеграционные тесты. Они используются и работают на разных этапах цикла разработки.

Модульные тесты

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

Итак, для базы данных нужно иметь что-то вроде:

IRespository

List<Product> GetProducts<String Size, String Color);

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

Интеграционные тесты

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

  • Окружающая среда Здоровье Стабильность Готовность
  • Тестирование реальной вещи

Эти тесты иногда сложнее выполнить, так как нам может потребоваться настроить и / или удалить их. Попробуйте добавить продукт. Мы, вероятно, хотим добавить продукт, запросить его, чтобы увидеть, был ли он добавлен, а затем, когда мы закончим, удалите его. Мы не хотим добавлять 100 или 1000 «интегрированных» продуктов, поэтому требуется дополнительная настройка.

Интеграционные тесты могут оказаться весьма полезными для проверки среды и проверки работоспособности.

Один должен иметь оба.

  • Запустите юнит-тесты для каждой сборки.
  • Запустите интеграционные тесты для каждого развертывания.
Джон Рейнор
источник
Я бы порекомендовал запускать интеграционные тесты для каждой сборки, а не фиксировать и выдвигать. Зависит от того, сколько времени они занимают, но также полезно держать их быстро по многим причинам.
artbristol
@ArtBristol - Как правило, на нашем сервере сборки не настроена полная зависимость среды, поэтому мы не можем запускать там наши интеграционные тесты. Но если можно запустить интеграционные тесты там, пойти на это. После сборки у нас установлена ​​песочница для развертывания, которую мы используем для тестирования интеграции для проверки развертывания. Но каждая ситуация отличается.
Джон Рейнор
11

Тесты интеграции баз данных не плохие. Более того, они необходимы.

Возможно, ваше приложение разбито на слои, и это хорошо. Вы можете проверить каждый слой изолированно, издеваясь над соседними слоями, и это тоже хорошо. Но независимо от того, сколько слоев абстракции вы создаете, в какой-то момент должен быть слой, который выполняет грязную работу - фактически общается с базой данных. Если вы не проверяете это, вы не проверяете вообще. Если вы тестируете слой n с помощью имитации слоя n-1, вы оцениваете предположение, что уровень n работает при условии, что уровень n-1 работает. Чтобы это работало, вы должны как-то доказать, что слой 0 работает.

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

Заключение

Какова уверенность, полученная в результате модульного тестирования вашего абстрактного репозитория , слоев Ethereal Object-Relational-Mapper , Generic Active Record , теоретической персистентности , когда в конце концов ваш сгенерированный SQL содержит синтаксическую ошибку?

el.pescado
источник
Я думал добавить ответ, похожий на ваш, но вы сказали это лучше! По моему опыту, некоторые тесты на слое, который получает и хранит данные, спасли меня от горя.
Даниэль Холлинрейк,
Тем не менее, тесты интеграции баз данных плохие. У вас есть база данных в вашей линии CI / CD? Это кажется довольно сложным для меня. Гораздо проще издеваться над базой данных и создавать слой абстракции, чтобы использовать это. Мало того, что это гораздо более элегантное решение, оно настолько быстрое, насколько это возможно. Модульные тесты должны быть быстрыми. Тестирование вашей базы данных значительно замедляет ваши юнит-тесты до уровня, который не приемлем. Юниттесты не должны занимать> 10 минут, даже если у вас их тысячи.
Дэвид
@ Дэвид Есть ли у вас база данных в вашей линии CI / CD? Конечно, это довольно стандартная функция . Кстати, я не поддерживаю интеграционные тесты вместо юнит-тестов - я защищаю интеграционные тесты в сочетании с юнит-тестами. Быстрые юнит-тесты необходимы, но базы данных слишком сложны, чтобы полагаться на юнит-тесты с поддельными взаимодействиями.
el.pescado
@ el.pescado Я должен не согласиться. Если ваша связь с базой данных находится за слоем абстракции, это действительно легко издеваться. Вы можете просто решить, какой объект вернуть. Кроме того, тот факт, что что-то стандартное, не делает его хорошим.
Дэвид
@ Дэвид Я думаю, это зависит от того, как вы подходите к базе данных. Это деталь реализации или жизненно важная часть системы ? (Я склоняюсь к последнему) . Если вы рассматриваете базу данных как тупое хранилище данных, то да, вы можете обойтись без интеграционных тестов. Однако, если в базе данных есть какая-либо логика - ограничения, триггеры, внешние ключи, транзакции или ваш уровень данных использует собственный SQL вместо простых методов ORM, я чувствую, что одних модульных тестов будет недостаточно.
el.pescado
6

Вам нужны оба.

В вашем примере, если вы проверяли, что база данных находится в определенном состоянии, при findByKeywordзапуске метода вы возвращаете данные, которые ожидаете, что это прекрасный интеграционный тест.

В любом другом коде, использующем этот findByKeywordметод, вы хотите контролировать то, что подается в тест, чтобы вы могли возвращать нули или правильные слова для вашего теста или что-то еще, после чего вы высмеиваете зависимость от базы данных, чтобы точно знать, что будет делать ваш тест получать (и вы теряете накладные расходы на подключение к базе данных и проверку правильности данных в ней)

Фрум
источник
6

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

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

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

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

Например, если вы знаете, что ваше приложение будет полагаться на базу данных (и, возможно, на конкретную систему баз данных), насмешка над поведением базы данных ради этого часто будет пустой тратой времени. Механизмы баз данных (особенно СУБД) представляют собой сложные системы. Несколько строк SQL на самом деле могут выполнять большую работу, которую было бы сложно смоделировать (на самом деле, если ваш SQL-запрос имеет длину в несколько строк, скорее всего, вам потребуется гораздо больше строк Java / PHP / C # / Python код для получения того же результата внутри): дублирование логики, которую вы уже реализовали в БД, не имеет смысла, и проверка этого тестового кода сама по себе станет проблемой.

Я бы не стал относиться к этому как к проблеме модульного тестирования по сравнению с интегрированным тестом , а скорее смотрю на объем тестируемого объекта. Общие проблемы модульного и интеграционного тестирования сохраняются: вам нужен достаточно реалистичный набор тестовых данных и тестовых случаев, но также достаточно маленький для быстрого выполнения тестов.

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

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

  • Если ваше приложение просто следует модели CRUD, где у вас есть уровень абстракции, который позволяет вам переключаться между любыми СУБД с помощью простых средств настройки конфигурации, скорее всего, вы сможете работать с фиктивной системой довольно легко (возможно, размытие) линия между модульным и комплексным тестированием с использованием СУБД в памяти).
  • Если ваше приложение использует более сложную логику, то, что было бы специфично для одного из SQL Server, MySQL, PostgreSQL (например), тогда, как правило, было бы более целесообразно иметь тест, использующий эту конкретную систему.
Bruno
источник
«Многие приложения сегодня просто не будут работать вообще, если их сервер базы данных выйдет из строя» - это действительно важный момент!
el.pescado
Хорошее объяснение границ сложных имитаций, например использование другого языка для имитации SQL. Когда тестовый код становится настолько сложным, что кажется, что его нужно протестировать самому, это запах QA.
dodgethesteamroller
1

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

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

Однако часто забываемая и несколько дорогая альтернатива / компаньон для насмешек - это «виртуализация» .

Можете ли вы раскрутить временный, находящийся в памяти, но «настоящий» экземпляр БД для тестирования одной функции? да ? там у вас есть лучший тест, который проверяет фактические данные, сохраненные и извлеченные.

Теперь можно сказать, что вы превратили юнит-тест в интеграционный тест. Существуют различные мнения о том, где провести черту для классификации между юнит-тестами и интеграционными тестами. ИМХО, «юнит» - это произвольное определение и должно соответствовать вашим потребностям.

SD
источник
1
это, кажется, просто повторяет высказанные и объясненные в предыдущем ответе замечания, которые были опубликованы несколько часов назад
коммент
0

Unit Testsи Integration Testsявляются orthgonal друг к другу. Они предлагают другой взгляд на приложение, которое вы создаете. Обычно вы хотите оба . Но момент времени отличается, когда вы хотите, какие виды тестов.

Наиболее часто вы хотите Unit Tests. Модульные тесты фокусируются на небольшой части тестируемого кода - то, что именно называется, unitостается читателю. Но та цель проста: получение быстрых обратной связи , когда и где ваш код сломался . Тем не менее, должно быть ясно, что вызовы фактической БД являются ненулевыми .

С другой стороны, есть вещи, которые можно тестировать только в тяжелых условиях без базы данных. Возможно, в вашем коде есть условие состязания, и при обращении к БД возникает нарушение, unique constraintкоторое может быть выдано только в том случае, если вы действительно используете свою систему. Но такие тесты дороги, вы не можете (и не хотите) запускать их так часто, как unit tests.

Томас Джанк
источник
0

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

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

Фактически, какое-то время я уже знал о TDD и Behavior Driven Design (BDD) и думал о способах его использования, но сложно добавить модульные тесты задним числом. Возможно, я ошибаюсь, но написание теста, охватывающего больше кода от начала до конца с включенной базой данных, кажется гораздо более полным и более приоритетным тестом для написания, который охватывает больше кода и является более эффективным способом написания тестов.

На самом деле, я думаю, что что-то вроде Behavior Driven Design (BDD), которое пытается тестировать от начала до конца на доменно-специфическом языке (DSL), должно быть подходящим способом. У нас есть SpecFlow в мире .Net, но он начался как открытый исходный код с Cucumber.

https://cucumber.io/

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

Согласно Stack Overflow, насмешка используется, когда реальные объекты нецелесообразно включать в модульный тест.

https://stackoverflow.com/questions/2665812/what-is-mocking

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

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

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

Соучредитель Stack Exchange не убежден в преимуществах 100% покрытия модульных тестов. Я тоже нет. Я бы взял более полный «интеграционный тест», который поразил бы базу данных, а не поддерживал кучу имитаций базы данных в любой день.

https://www.joelonsoftware.com/2009/01/31/from-podcast-38/

user3198764
источник
настолько очевидно, что вы не понимаете разницы между модульными и интеграционными тестами
BЈовић
Я думаю, что это зависит от проекта. В небольших проектах с меньшими ресурсами, когда разработчик несет большую ответственность за тестирование и регрессионное тестирование из-за нехватки тестеров и синхронизации документации с кодом, если я собираюсь потратить какое-то время на написание тестов, то это будут те, которые дает мне большую отдачу за мой доллар. Я хочу убить как можно больше птиц одним камнем. Если большая часть моей логики и ошибок связана с хранимыми процедурами базы данных, генерирующими отчеты, или с интерфейсом JavaScript, то полное покрытие модульных тестов на среднем уровне мало поможет.
user3198764
-1

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

С настоящими юнит-тестами вы тестируете в пределах песочницы, и это должно быть ясно. Если разработчик написал запрос SQL, который потерпел неудачу в QA / PROD, это означает, что он даже не тестировал его один раз до того времени.

vidalsasoon
источник
+1 за «вы не можете их контролировать (они могут пройти во время фазы интеграционного тестирования, но потерпеть неудачу в производстве)» .
Тулаинс Кордова
Вы можете контролировать их до удовлетворительной степени.
el.pescado
Я понимаю вашу точку зрения, но я думаю, что раньше это было более верно, чем сегодня? С помощью автоматизации и инструментов (таких как Docker) вы можете точно и надежно реплицировать и повторить настройку всех ваших бинарных / серверных зависимостей для комплектов тестов интеграции. Конечно, да, физическое оборудование (и сторонние службы и т. Д.) Может выйти из строя.
mindplay.dk
5
Я абсолютно не согласен. Вы должны написать (дополнительные) интеграционные тесты, потому что внешние зависимости могут потерпеть неудачу. Внешние зависимости могут иметь свои причуды, которые вы, скорее всего, упустите, когда будете все издеваться.
Пол Керчер
1
@PaulK все еще размышляет, какой ответ пометить как принятый, но я склоняюсь к тому же выводу.
mindplay.dk