Тестируемый код и глобальные константы

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

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

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


использовать PHPUnit в . Он запускает данный файл до проведения каких-либо тестов.