ste*_*lin 6 php phpunit unit-testing
在这里,我正在编写一个小应用程序,其唯一目的是获得更好的OOP /可测试代码习惯.爱它,顺便说一下!
我正在努力吸收开发"可测试代码"背后的方法,主要是通过阅读Sebastien Bergmann,Misko Hevery和Giorgio Sironi等单位测试福音传教士的帖子.
我所接受的困难之一是滥用静态方法,依赖于依赖于对象的对象的对象.目前,我被困在全球范围内.在我的应用程序开始时,我加载了一个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");
Run Code Online (Sandbox Code Playgroud)
如何根据此常量的状态测试应用程序类以进行正确的错误处理?
起初我的想法是简单地将全局常量移动到类常量而不是在我的init类中,这解决了这个特定类的情况,但我不满意这个过程.我的意思是,是否应该简单地避免在严格意义上的一个可能值总是不是"真正"常量的站点范围常量?
我无法想象测试人员必须为每个类编写2个测试套件,即initClassDebugTest.php和initClassProdTest.php,除非phpUnit可以某种方式重置全局状态?应该避免使用这种方式的全局常量吗?我有一种奇怪的直觉,我根本不应该使用常数.我很想知道测试savy编码器如何在运行时处理具有2个可能值的全局定义.
这主要取决于您如何创建对象以及有多少类访问 this 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
Run Code Online (Sandbox Code Playgroud)
类似这样的问题通常可以通过将“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();
Run Code Online (Sandbox Code Playgroud)
等等。您可以逐步减少全局状态的数量,直到摆脱定义而只剩下配置设置。
当谈到测试确实有效的类时,您现在以以太方式获胜,因为日志记录是可注入的,并且您可以传入模拟进行测试。
到目前为止,第一个想法..如果您认为这对您不起作用,可以提供一个使用 APPMODE 的示例