在这里,我正在编写一个小应用程序,其唯一目的是获得更好的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");
如何根据此常量的状态测试应用类以进行正确的错误处理?
起初我的想法是简单地将全局常量移动到类常量而不是在我的init类中,这解决了这个特定类的情况,但我不满意这个过程。我的意思是,如果在一个可能的值总是的严格意义上,是否应该简单地避免不是“真正”常量的站点范围常量?
我无法想象测试人员必须为每个类编写2个测试套件,即initClassDebugTest.php和initClassProdTest.php,除非phpUnit可以某种方式重置全局状态?应该避免使用这种方式的全局常量吗?我有一种奇怪的直觉,我根本不应该使用常数。我非常想知道测试savy编码器如何在运行时处理具有2个可能值的全局定义。
答案 0 :(得分:4)
这主要取决于您创建对象的方式以及有多少类访问此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的示例
答案 1 :(得分:0)
使用phpunit的--bootstrap
选项。它在任何测试完成之前运行给定的文件。