О зависимостях в модульном тестировании

#unit-testing #testing #dependencies

#модульное тестирование #тестирование #зависимости

Вопрос:

Я новичок в модульном тестировании, но склонен думать, что верю в красиво написанный код и правильно спроектированные архитектуры.

Мой вопрос. Не слишком ли много внимания в модульных тестах уделяется зависимостям между объектами? Что вы делаете, когда ваш модульный тест завершается неудачей, потому что зависимость, которую ваш метод использовал для вызова befor, больше не вызывается (проектное решение) или ваш метод вызывает другой метод или зависимость (опять же проектное решение) Вы перепроектируете свои тесты? Если это так, то модульное тестирование очень мало помогает уменьшить количество пар и улучшить связь между компонентами.

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

Ответ №1:

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

Чтобы разобраться с зависимостями, подумайте о том, какие зависимости вызывают у вас проблемы.

Внешние зависимости

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

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

Зависимости объектов

Если вы беспокоитесь о зависимостях кода (например, ваш тест завершится неудачей, если подпись частного метода будет изменена), то вы тестируете на неправильном уровне абстракции. Под этим я подразумеваю, что ваши тесты вызывают общедоступные API, а не частные. Чтобы закрепить этот момент, используйте interfaces for your objects для обеспечения ожидаемого контракта для объекта, который его реализует.

Я бы также рекомендовал вам попробовать использовать фреймворк-макет, такой как RhinoMocks, Moq или TypeMock

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

Комментарии:

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

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

3. Это то, что также гудело у меня в голове.

Ответ №2:

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

Комментарии:

1. да, приходите посмотреть, как там написано 99% кода. Зависимости есть везде, и вы вряд ли сможете написать метод, который не вызывает метод для другого объекта. Наглядным примером является связь между контроллерами и объектами DAO в Java

2. Да, конечно, но тогда мы говорим об интеграционных тестах, а не о модульных тестах. В этом примере вы задали вопрос: может ли контроллер проходить модульное тестирование? Я бы сказал, нет, потому что контроллер не alone…so вы должны провести интеграционный тест.

Ответ №3:

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

Тестирование реализации приводит к хрупким тестам, что мешает при рефакторинге.

Комментарии:

1. Ну, как я могу проверить, что мой метод возвращает некоторые результаты для определенного набора параметров, если тест проваливается, потому что зависимость, которую вызывал мой метод, просто не была объявлена 🙂

2. У класса есть обязанности (желательно один) и сотрудничество. Если вы измените collobaration (т. Е. Дизайн), а не обязанности, то тесты не должны прерываться.