Средства доступа для модульного тестирования (геттеры и сеттеры)


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

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

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

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

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

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

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

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

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

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

Author: markus, 2011-02-14

3 answers

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

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

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

.

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

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

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

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

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

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

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

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

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

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

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

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

 6
Author: edorian, 2011-02-14 11:16:41

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

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

Попробуйте изолировать свои тестовые случаи - напишите тест для SUT (тестируемого субъекта ), который проверяет его правильность без использования других методов (кроме моего примера выше). Чем больше вы изолируете чем больше тест, тем больше ваши тесты выявляют проблему.

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

Для тестировщиков черного ящика рекомендуется использовать phpunit в строгом режим и использовать @обложки, чтобы скрыть сопутствующее покрытие.

Когда вы пишете модульный тест, ваш тест для класса 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), в противном случае удалите его. В случае, если он используется только в том же классе, сделайте его приватным/защищенным. Не применяйте это правило к библиотечному коду.

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

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

 7
Author: DanielaWaranie, 2013-06-30 10:00:38

Это распространенный вопрос, но, как ни странно, я не могу найти обманщика на 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));
}
 3
Author: Gishu, 2011-02-15 05:29:08