Controlled Code and Global Constants

Here I am writing a small application for the sole purpose of acquiring the best OOP / test code skills. And love him, by the way!

I try to assimilate the “test code” development methodology, mainly by reading messages from test evangelists such as Sebastian Bergmann, Mishko Hevery and Giorgio Sironi.

Among the difficulties that I learned is the abuse of static methods, objects that depend on objects that depend on objects. Currently, I adhere to global wide constants. At the beginning of my application, I load one single CONSTANT, which simply sets the application mode to debug or 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"); 

How can I test application classes for correct error handling depending on the state of this constant?

My first thought was to simply move the global constant into the class constant instead into my init class and solve this case for this particular class, but I am not satisfied with this procedure. I mean, should you just avoid constant constants that are not “true” constants in the strict sense of one possible value?

I can’t imagine that testers had to write 2 test suites for each class, i.e. initClassDebugTest.php and initClassProdTest.php, if phpUnit cannot somehow reset the global state? Should global constants be avoided this way? I have a strange feeling that I should not use constant here at all. I would be very curious to know how the guardian test programs will handle global definitions with two possible values ​​at runtime.

+6
source share
2 answers

It mainly depends on how you create your objects and how many classes access this APPMODE .

See what APPMODE does:

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

Something like this is usually solved by passing in "DebugLogger" and "DontSendEmailMailer" to the classes that should send mail.

To do this, you need only a few factories (or something else that you use to create a graph of objects) that you need to know about “production” and “development”.

The classes that make your actual business logic should not know if it works in production or not. This would mean that the developer of each class would have to take care of this, and each class would have to be modified if you ... say .. have an "intermediate" environment. It introduces a lot of global status, which, as you find, is difficult to verify.

If errors should be displayed or not resolved in the models of your php.ini or in the application boot buffer and should not concern the rest of your application.

I would start to move this "debugging" functionality from classes that require your APPMODE parameter, and move them to highlighted classes (logs, mailing lists, ...). The real thing (which actually sends mail) and the debugging thing (maybe it writes letters to disk?). Both of these classes can be tested correctly (testing a null logger is pretty simple;)), and you only need to do this switch a few times.

 if($config->evironment() == "debug") { $logger = new DisplayEverythingLogger(); } else { $logger = new OnlyLogErrorsToTextfileLogger(); } $neededModel = new ClassThatDoesActualWork($logger); $controllerOrSomething = new ControllerOrWhatEveryDoesYourWorkflow($neededModel); $controllerOrSomething->dispatch(); 

etc. You can reduce the amount of global state step by step until you get rid of the definition and get only configuration settings.

When it comes to testing a class that works, you have now won the broadcast because registration has been implemented and you can go through the mock for testing.


So far for the first idea .. If you think this does not work, perhaps you can give an example of using APPMODE

+4
source

Use the phpunit option --bootstrap . It runs this file before any tests are performed.

0
source

Source: https://habr.com/ru/post/887901/


All Articles