Является ли композиция объектов без внедрения зависимостей плохой вещью? - PullRequest
3 голосов
/ 03 мая 2009

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

<?php
class aSampleClass {
    private $dependency;
    public function __construct() {
        $this->dependency = new otherClass;
    }
}

Этот игрушечный пример легко преобразовать в использование внедрения зависимостей, передав экземпляр объекта otherClass в качестве параметра конструктору, но это не всегда так. Является ли композиция объектов вышеупомянутой формы (где оператор new используется непосредственно в реализации класса) плохой вещью? Следует ли вам всегда пытаться написать класс, чтобы он мог быть полностью протестирован в отрыве от его ассоциаций?

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

<?php
    class anotherSampleClass {
        public function getTimeDifferencePhrase() {
            $now = new date_Time;
            $then = new date_Time(time()-60*60*24);
            return $now->relativeTimePhrase($then);
        }
    }

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

Мысли?

Ответы [ 4 ]

2 голосов
/ 03 мая 2009

Это зависит от что вы тестируете. Dependency Injection решает проблему тестирования вашего класса, не беспокоясь о его зависимости от внешних сервисов (которые могут не работать, не иметь тестовых данных или иным образом не подходить для модульного теста).

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

Однако вы бы проверили, что ваш getRelativeTimeDifferencePhrase правильно возвращает "24 часа назад", когда прошло 60 * 60 * 24 seconds.

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

Наличие в вашем экземпляре класса RealTimeService не оставит вам способа внедрить ваш MockTimeService - так что вы сможете жестко кодировать, что это такое time(), и тогда вы в конечном итоге передадите ITimeService своему конструктору , Теперь у вас есть инъекция зависимости. ;)

1 голос
/ 19 ноября 2009

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

Я думаю, что внедрение зависимостей велико, если оно не нарушает архитектуру. Многие люди говорят, что использование оператора new в конструкторе плохо, и вместо этого экземпляр должен быть передан в конструктор, но они ошибаются. Это должно зависеть от домена. Есть ситуации, когда это может даже привести к путанице, особенно в языках без сборки мусора. Например, эмпирическое правило в C ++ гласит, что создатель уничтожает объект. Итак, если телефон с батареей разрушен, кто собирается уничтожить батарею? Телефон или какой-либо объект передал его в телефон? Но в некоторых ситуациях вы захотите передать батарею в телефон. Например, если вы моделируете фабрику.

Итак, чтобы ответить на ваш вопрос "Является ли композиция объектов без внедрения зависимостей плохой вещью?" - это зависит от предметной области, которую вы моделируете, жертвовать дизайном ради тестируемости - это плохо, ИМО. Если вы найдете что-то непроверенное, посмотрите, правильно ли ваш дизайн. Я обычно смотрю, смогу ли я ввести внедрение зависимости. Если это не может быть и речи, тогда я посмотрю, смогу ли я внедрить фабричные методы Если нет, тогда я посмотрю, смогу ли я сделать что-нибудь еще.

0 голосов
/ 03 мая 2009

Нет жестких правил для чего-то подобного. Некоторые пуристы скажут, что вы должны вводить зависимость, в то время как другие пойдут на более прагматичный подход. Поскольку само ВО не имеет каких-либо зависимостей, я бы, вероятно, применил принцип KISS и сказал бы, что вполне нормально «добавить» его в объект. Это особенно верно, VO находится в том же модуле (в терминах DDD). Более того, создание экземпляра VO в объекте не делает его менее тестируемым.

0 голосов
/ 03 мая 2009

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

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

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

Итак, короткий ответ: обычно это хорошо, но далеко не всегда необходимо.

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