Тестируемый код и глобальные константы
здесь я пишу небольшое приложение с единственной целью приобретения лучших привычек ООП / тестируемого кода. И любить его, кстати!
Я стремлюсь ассимилировать методологию разработки "тестируемого кода", в основном читая сообщения от евангелистов модульного тестирования, таких как Себастьян Бергманн, Миско Хевери и Джорджио Сирони.
среди трудностей, которые я усвоил, является неправильное использование статических методов, объектов, которые зависят от объектов, которые зависят от объектов. В настоящее время я застрял на глобальной константы. В начале моего приложения я загружаю одну константу, которая просто устанавливает режим приложения в 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 может как-то сбросить глобальное состояние? Следует ли избегать использования глобальных констант таким образом? У меня странное чувство, что я не должен использовать константу здесь вообще. Мне было бы очень любопытно узнать, как тест savy кодеры там будут обрабатывать глобальные определения с 2 возможными значениями во время выполнения.
2 ответов
Это в основном зависит от того, как вы создаете свои объекты и сколько классов получить доступ к этому 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 или в вашем приложении bootstrap и не должны касаться остальных приложения.
Я бы начал перемещать эту функцию "отладки" из классов, которым нужна настройка APPMODE, и переместить ее в выделенный (ведение журнала, рассылка,...) учебные занятия. Реальная вещь (которая фактически отправляет почту) и отладочная вещь (которая, возможно, пишет письма на диск?). Оба этих класса могут быть протестированы правильно (тестирование нулевого регистратора довольно легко;)), и вам нужно сделать этот переключатель только несколько раз.
if($config->evironment() == "debug") {
$logger = new DisplayEverythingLogger();
} else {
$logger = new OnlyLogErrorsToTextfileLogger();
}
$neededModel = new ClassThatDoesActualWork($logger);
$controllerOrSomething = new ControllerOrWhatEveryDoesYourWorkflow($neededModel);
$controllerOrSomething->dispatch();
и так далее. Вы можете уменьшить количество глобального состояния шаг за шагом, пока вы не избавитесь от определения и не получите только настройку конфигурации.
когда дело доходит до тестирования класса, который работает, вы теперь выиграли эфирный путь, потому что ведение журнала можно вводить, и вы можете пройти в макет для тестирования.
пока для первой идеи.. если вы думаете, что это не работает для вас, возможно, приведите пример, где используется APPMODE