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

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

Для использования следующих методов:

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

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

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

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

  • Только один тестовый метод?

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

Изменить после комментария:

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

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

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

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

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

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

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

Ответ 2

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

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

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

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

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

Когда вы пишете unit test, ваш тест на классе 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 "достаточно равен" для производственного кода для получения значимого результата.

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

Ответ 3

Это общий вопрос, но странно не удается найти обман на 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));
}