Подтвердить что ты не робот

Что более важно, проверяемость кода или соблюдение принципов ООП?

В моей команде эволюция TDD включает в себя то, что кажется отходом от традиционного oop.

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

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

Каковы ваши мысли?

4b9b3361

Ответ 1

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

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

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

Но очевидный вопрос: действительно ли вам нужно проверять каждый частный метод? Они не являются частью публичного договора класса и не могут быть значимыми в изоляции. Публичные методы важны для тестирования, потому что они имеют определенную цель, они должны выполнять этот конкретный контракт и оставлять объект в согласованном состоянии и так далее. Они по сути проверяются, так что частный метод может и не быть. (Кто заботится о том, что делает частный метод? Это не часть договора класса)

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

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

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

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

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

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

Ответ 2

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

  • не должно быть конфликта между принципами OO и TDD, потому что
  • частные методы не нуждаются в модульной проверке, только публичные.

Ответ 3

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

Вводя "вспомогательные объекты" в классы, на самом деле хорошо. Однако вы не должны думать о них как о вспомогательных объектах. Это обычные объекты, мы надеемся, на другом уровне абстракции. Они в основном являются стратегиями, которые определяют, как заполняются детали алгоритмов более высокого уровня. (Обычно я вставляю их с помощью конструктора, а также предоставляю другой конструктор, который автоматически использует производственную реализацию по умолчанию, если таковой имеется.) Остерегайтесь, хотя - по моему опыту, тоже может быть преувеличено. Посмотрите http://martinfowler.com/articles/mocksArentStubs.html на некоторые интересные мысли по этой теме.

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

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

Ответ 4

Хороший дизайн OO - это больше, чем инкапсуляция, больше, чем частные методы.

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

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

Также существует принцип Open/Closed. Вводя вспомогательные классы, вы допускаете полиморфную замену поведения.

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

Ответ 5

Поддержание работоспособности более важно.

Не пропустите тот факт, что и модульное тестирование, и ООП имеют общую цель.

Ответ 6

ООП - это инструмент, а не цель

Ответ 7

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

Ответ 8

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

Мы переписываем целую кучу синглетов, чтобы использовать DI/IOC прямо сейчас, чтобы мы могли протестировать их (скоро вы окажетесь рядом с вами).

Ответ 9

Вы также можете исследовать инъекцию зависимостей в качестве способа экстернализации некоторых вспомогательных классов

Ответ 10

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

Ответ 11

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

[assembly: InternalsVisibleTo("MyAssembly.Tests")]

Ответ 12

Я не знаком ни с одним конфликтом между ними. Высокое сцепление и низкое сцепление являются ядром OO, и это также является основой тестирования.

Ответ 13

Как обычный пользователь Intellisense, требование о том, чтобы все методы были общедоступными, приводило меня в бешенство. Я бы придерживался ООП только на этой основе.

Ответ 14

Почему бы просто не использовать макрос вместо ключевого слова private. Когда вы компилируете с помощью "testmode", эти методы являются общедоступными. В противном случае они являются частными. С макросом вы все равно получите предупреждения компилятора, когда публично используете свои частные методы, как только вы компилируете не в режиме тестирования. Интересно отметить, что, если ваши частные методы терпят неудачу, их модульные тесты не подразумевают ошибку в вашей программе, хотя она, скорее всего, эквивалентна функции "CauseBSOD", которая никогда не вызывается. Это сильно поврежденная функция (предполагая, что причиной BSOD не является), но это не ошибка в отношении пользователей.

Ответ 15

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

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