Тестируемый код и глобальные константы - PullRequest
6 голосов
/ 12 мая 2011

Здесь я пишу небольшое приложение с единственной целью - приобрести лучшие привычки ООП / тестируемого кода.И любить это, кстати!

Я стремлюсь усвоить методологию разработки «тестируемого кода», в основном, читая посты таких евангелистов, как Себастьен Бергманн, Миско Хевери и Джорджио Сирони.

Среди трудностей, которые я усвоилявляется неправильным использованием статических методов, объектов, которые зависят от объектов, которые зависят от объектов.В настоящее время я застрял на глобальных постоянных.В начале моего приложения я загружаю один единственный CONSTANT, который просто устанавливает режим приложения в debug или prod:

/**
 *  APP_MODE values:
 *
 *  PROD   Production, no errors displayed email sent on error, logs to 
 *         logs/app-<date-time>.log.
 *
 *  DEBUG: All warnings and errors displayed, emails disabled and log messages 
 *         sent to console. Whether in-memory modifications to configuration 
 *         data are allowed
 */
 define("APPMODE", "DEBUG");

Как можно протестировать классы приложения для правильной обработки ошибок в зависимости от состояния этой константы?

Сначала я думал просто переместить глобальную константу в константу класса вместо этого в моем классе инициализации, и это решает проблему для этого конкретного класса, но я не удовлетворен этой процедурой.Я имею в виду, следует ли просто избегать постоянных сторон, которые не являются «истинно» константами в строгом смысле одного возможного значения всегда ?

Я не могу себе представить, что тестировщики должны написать 2 набора тестов для каждого класса, то есть initClassDebugTest.php и initClassProdTest.php, если phpUnit не может каким-то образом сбросить глобальное состояние?Следует ли избегать использования глобальных констант таким образом?У меня странное чувство, что я не должен использовать здесь константу вообще.Мне было бы очень любопытно узнать, как тестирующие здравомыслящие кодеры будут обрабатывать глобальные определения с 2 возможными значениями во время выполнения.

Ответы [ 2 ]

4 голосов
/ 12 мая 2011

Это в основном зависит от того, как вы создаете свои объекты и сколько классов обращаются к этому APPMODE.

Давайте посмотрим, что делает APPMODE:

 *  DEBUG: All warnings and errors displayed, emails disabled and log messages 
 *         sent to console. Whether in-memory modifications to configuration 
 *         data are allowed

Нечто подобное обычно решается путем передачи "DebugLogger" и "DontSendEmailMailer" классам, которым нужно отправлять почту.

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

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

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

Я бы начал выводить эту функцию «отладки» из классов, для которых требуется настройка APPMODE, и переместил бы ее в выделенные (ведение журнала, рассылка, ...) классы. Реальная вещь (которая на самом деле отправляет почту) и вещь отладки (которая может записывать почту на диск?). Оба этих класса могут быть протестированы надлежащим образом (тестирование нулевого логгера довольно просто;)) и вам нужно сделать это переключение только несколько раз.

if($config->evironment() == "debug") {
    $logger = new DisplayEverythingLogger();
} else {
    $logger = new OnlyLogErrorsToTextfileLogger();
}


$neededModel = new ClassThatDoesActualWork($logger);

$controllerOrSomething = new ControllerOrWhatEveryDoesYourWorkflow($neededModel);
$controllerOrSomething->dispatch();

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

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


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

0 голосов
/ 12 мая 2011

Используйте опцию phpunit --bootstrap.Он запускает указанный файл перед выполнением любых тестов.

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