Нужно ли только макетировать внешние зависимости в модульном тесте?Как насчет внутренних зависимостей? - PullRequest
0 голосов
/ 17 февраля 2011

Нужно ли только макетировать внешние зависимости в модульном тесте?

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

Является ли интеграционный тест тестом, который проверяет зависимости в целом, или мне нужно различать внутренние и внешние зависимости?

Примером может служить метод, имеющий 2000 строк кода с 5 вызовами методов (все методы, поступающие из одной сборки).

Ответы [ 3 ]

5 голосов
/ 17 февраля 2011

Как правило, надлежащим модульным тестом является проверка только этого единственного куска кода. Таким образом, в таком сценарии вы начинаете задавать себе вопрос о соединении этих двух классов. Зависит ли класс А от реализации класса В? Или просто нужно предоставить экземпляр типа B (обратите внимание на разницу между классом и типом)?

Если последнее, то издевайтесь, потому что вы не тестируете класс B, просто класс A.

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

Редактировать: (в ответ на ваш комментарий) Я думаю, что ключевую вещь, которую нужно помнить при выполнении этого (а ретроспективное юнит-тестирование в унаследованную систему действительно, очень сложно), это мысленно отделить понятия класса и типа.

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

Указывает ли тип A в своем контракте, что для реализации потребуется экземпляр типа B? Или класс А разрешает его экземпляр внутренне? Требуется ли для типа A указать это, или возможно, что различным реализациям типа A не потребуется экземпляр типа B?

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

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

4 голосов
/ 19 февраля 2011

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

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

Короче говоря,Существуют безопасные рефакторинги, которые вы можете сделать, не рискуя сломать вещи, которые могут помочь вам начать работу.Есть и другие рефакторинги, которые требуют тестов для защиты работы. Тесты необходимы при рефакторинге кода .Это, конечно, не дает 100% гарантии того, что все не сломается, потому что может быть так много скрытых «функций» и сложности, о которых вы не сможете знать при запуске.В зависимости от базы кода объем работы, которую вам нужно выполнить, сильно варьируется, но для больших баз кода обычно много работы.

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

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

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

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

Удачи и не торопитесь!;)

1 голос
/ 18 февраля 2011

Вообще говоря, метод с 2000 строками кода просто ПЛОХО. Я обычно начинаю искать причины для создания новых классов - даже не методов, а классов - когда мне приходится использовать ключ pagedown более трех или четырех раз, чтобы просмотреть его (а сворачиваемые области не учитываются).

Итак, да, вам нужно избавиться от зависимостей снаружи и внутри сборки, и вам нужно подумать об ответственности класса. Похоже, что у этого слишком большой вес на плечах, и кажется, что это совсем близко к невозможности написать юнит-тесты. Если вы думаете о тестируемости, вы автоматически начнете внедрять зависимости и сокращать свои классы, и BAM !!! красивый и красивый код! : -)

С уважением, Morten

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