Агенты для тестирования модулей (геттеры и сеттеры)

Учитывая следующие методы:

public function setFoo($foo) { $this->_foo = $foo; return $this; } public function getFoo() { return $this->_foo; } 

Предполагая, что в будущем они могут быть более сложными:

  • Как бы вы написали модульные тесты для этих методов?
  • Только один метод тестирования?
  • Должен ли я пропустить эти тесты?
  • Как насчет покрытия кода?
  • Как насчет аннотации @covers ?
  • Может быть, какой-то универсальный метод тестирования для реализации в абстрактном тестовом случае?

(Я использую Netbeans 7)

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

К qoute из комментария блога Себастьяна Бергмана :

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

Итак, как насчет покрытия кода?

Хороший вопрос,

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

Особенно, если не использовать TDD, это имеет дополнительное преимущество, показывающее мне настройки, которые я не использую в своих unittests, показывая мне, что эфир мои тесты неполны или что сеттер не используется / не нужен. «Если я могу выполнить весь« реальный »код, не используя этот установщик, почему он там».

Когда я использую свободный набор, я иногда пишу тест, проверяющий «беглую» часть сеттеров, но обычно это рассматривается в других тестах.

Чтобы ответить на ваш список:

  • Только один метод тестирования?

Это мой наименее любимый вариант. Все или нет. Тестирование только одного – это непросто для других людей понять и выглядеть «случайным» или нужно документировать в некотором роде.

Редактировать после комментария:

Да, для «тривиального» теста get / set я использовал бы только один метод для каждого свойства, возможно, в зависимости от случая даже только один метод для всего класса (для объектов с множеством геттеров и сеттеров я не хочу писать / поддерживать многие тесты)

  • Как бы вы написали модульные тесты для этих методов?
  • Должен ли я пропустить эти тесты?

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

  • Как насчет покрытия кода?
  • Как насчет аннотации @covers?

С помощью @covers мой прием всегда «использует его везде или вообще не использует». Смешивание двух «стилей» тестирования отнимает некоторые из преимуществ аннотации и выглядит «незавершенным» для меня.

  • Может быть, какой-то универсальный метод тестирования для реализации в абстрактном тестовом случае?

Для чего-то вроде объектов ценности, которые могут работать хорошо. Это может сломаться (или усложняется), когда вы передаете объекты / массив с типом намекания, но я предпочел бы это прежде, чем написать ручные тесты для 500 геттеров и сеттеров.

Если вы делаете TDD, вы должны написать тест для getter и setter. слишком. Не пишите ни одной строки кода без проверки на нее, даже если ваш код очень прост.

Это своего рода религиозная война, чтобы использовать тандем геттера и сеттера для вашего теста или изолировать каждого, обратившись к защищенным членам класса, используя возможности модульного тестирования. Являясь тестером черного ящика, я предпочитаю привязывать свой код модульного теста к публичному api, а не привязывать его к конкретным деталям реализации. Я ожидаю перемен. Я хочу призвать разработчиков реорганизовать существующий код. И внутренности класса не должны влиять на «внешний код» (в этом случае единичные тесты). Я не хочу прерывать модульные тесты, когда меняются внутренние переменные, я хочу, чтобы они ломались при изменении public api или при изменении поведения. Хорошо, хорошо, в случае неудачного модульного теста не указывайте на единственный и единственный источник проблем. Мне нужно посмотреть в getter И сеттер, чтобы выяснить, что вызвало проблему. В большинстве случаев ваш получатель очень прост (менее 5 строк кода: например, возврат и необязательная проверка нуля с исключением). Таким образом, проверка этого в первую очередь не имеет большого значения и не требует много времени. И проверка счастливого пути сеттера в большинстве случаев немного сложнее (даже если у вас есть некоторые проверки проверки).

Попробуйте изолировать ваши тестовые примеры – напишите тест для SUT (Subject under test), который проверяет правильность его использования без повтора других методов (кроме моего примера выше). Чем больше вы изолируете тест, тем больше ваших проблем выявляет проблему.

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

Лучше всего использовать тестеры черного ящика для использования phpunit в строгом режиме и использовать @covers для скрытия покрытия.

Когда вы пишете единичный тест, ваш тест на классе A должен выполняться независимо от класса B. Поэтому ваши модульные тесты для класса A не должны вызывать метод / класс класса B.

Если вы хотите идентифицировать устаревший геттер / сеттер и другие «мертвые» методы (которые не используются производственным кодом), используйте для этого статический анализ кода. Показатель, который вас интересует, называется «Афферентная связь на уровне метода (MethodCa)». К сожалению, эта метрика (ca) недоступна на уровне метода в PHP Depend (см. http://pdepend.org/documentation/software-metrics/index.html и http://pdepend.org/documentation/software-metrics /afferent-coupling.html ). Если вам это действительно нужно, не стесняйтесь вносить свой вклад в PHP Depend. Возможность исключать вызовы из одного класса была бы полезной для получения результата без «побочных» вызовов. Если вы идентифицируете «мертвый метод», попытайтесь выяснить, будет ли он использоваться в ближайшем будущем (аналог другого метода с @depricated аннотацией), иначе удалите его. Если он используется только в том же классе, сделайте его приватным / защищенным. Не применяйте это правило к библиотечному коду.

План B: Если у вас есть приемочные тесты (интеграционный тест, регрессионный тест и т. Д.), Вы можете запустить этот тест без проведения единичных тестов в одно и то же время и без строгого режима phpunits. Это может привести к очень сходному результату покрытия кода, как если бы вы проанализировали ваш производственный код. Но в большинстве случаев ваши не-модульные тесты не так сильны, как ваш производственный код. Это зависит от вашей дисциплины, если этот план B «достаточно равен» для производственного кода для получения значимого результата.

Дальнейшее чтение: – Книга: Прагматический программист – Книга: Чистый код

Это общий вопрос, но странно не может найти обман на SO.

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

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

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

 [Test] public void UpdatesTogglePauseTooltipBasedOnState() { Assert.That(_mainViewModel.TogglePauseTooltip, Is.EqualTo(Strings.Main_PauseAllBeacons)); _mainViewModel.TogglePauseCommand.Execute(null); Assert.That(_mainViewModel.TogglePauseTooltip, Is.EqualTo(Strings.Main_ResumeAllBeacons)); _mainViewModel.TogglePauseCommand.Execute(null); Assert.That(_mainViewModel.TogglePauseTooltip, Is.EqualTo(Strings.Main_PauseAllBeacons)); }