支持单元测试的 PHP 前端控制器库

Posted

技术标签:

【中文标题】支持单元测试的 PHP 前端控制器库【英文标题】:PHP front controller library with support for unit testing 【发布时间】:2011-09-10 15:01:07 【问题描述】:

我正在寻找一个(小型)库,它可以帮助我为我的 pet project 干净地实现 front controller 并将请求分派到单个控制器类。前端控制器/调度程序和控制器类需要完全可单元测试,而无需发送 HTTP 请求。

要求

PSR-0 兼容 可通过自己的PEAR channel 安装 支持单元测试: 检查是否发送了正确的 HTTP 标头 捕获输出以允许在单元测试中进行检查 最好使用 phpUnit 辅助方法来帮助检查输出(针对不同的输出类型,即 html、XML、JSON) 允许设置传入的 HTTP 标头、GET 和 POST 参数以及 cookie,而无需实际执行 HTTP 请求 需要独立使用 - 没有 db 抽象、模板等,因此胖框架都提供了

背景

SemanticScuttle 是一个必然会获得适当“C”支持的应用程序,它是一个现有的工作应用程序。库需要融入其中,并且需要与现有的结构和类一起工作。我不会重写它以匹配框架的特定所需目录布局。

应用程序已经有单元测试,但基于 HTTP 请求,这使得它们变慢。此外,当前在www 目录中拥有几十个.php 文件的旧方法并不是最易于管理的解决方案,这就是需要引入适当的控制器类的原因。总而言之,将有大约 20-30 个控制器。

以前的经验

总的来说,我对以前的一些项目中的 Zend Framework 非常满意,但它有几个缺点:

不是 pear 可安装的,因此我不能在我的 pear 可安装应用程序中将其用作依赖项 仅作为一个胖下载提供,因此我需要手动从中提取所需的位 - 用于每个 ZF 更新。 虽然 ZF 控制器存在单元测试支持,但它缺少一些高级实用程序功能,例如 json 断言、HTTP 状态代码和内容类型检查。

虽然这些观点似乎很挑剔,但它们对我来说很重要。如果我必须自己实现它们,我不需要使用外部库,而是自己编写。

我不想要的

*** 有一百万个“什么是最好的 PHP 框架”问题(1、2、3、4、5),但我不是在寻找那些,而是在寻找一个 特定的库,可帮助控制器。如果它是模块化框架的一部分,那很好。

我也知道PHP framework comparison website,但这无助于回答我的问题,因为那里没有列出我的要求。

而且我知道我可以自己构建这一切并发明另一个微框架。但为什么?已经有这么多,我只需要拥有我需要的一切。

相关问题

What's your 'no framework' PHP framework? How do you convert a page-based PHP application to MVC?

【问题讨论】:

not pear-installable 那又怎样?许多发行版都有一个用于维护当前安装版本的软件包。 only available as one fat download - 又一次,那又怎样?您只需下载并安装一次。 it's lacking some advanced utility functionality 很容易用你自己的扩展基础测试类并添加额外的断言。 @zerkms:我不会只安装一次。我需要升级和维护它。拥有一个梨形频道会有所帮助。 @cweiske:每个 linux 发行版的软件包中都有它。你用哪个?顺便说一句,用梨你也可以下载一个胖文件。 @zerkms:“使用梨,您还可以下载一个和一个胖文件” - 是的,这是一个问题,因为 ZF 没有在单独的模块中提供。你看我的问题 :) 另外,该软件也应该可以安装在 OSX 和 Windows 上。 @cweiske:当你想测试没有 HTTP 请求时,你写了一个要求:“检查是否发送了正确的 HTTP 标头”。我认为这行不通。您至少需要模仿请求标头来执行此类测试。 【参考方案1】:

非常了解 Symfony2,我可以向您保证,它绝对可以仅用于 MVC 中的“C”。模型和模板是完全免费的,而且通常都是从控制器中执行的,所以如果你不专门调用 Doctrine 或 Twig,你可以做你想做的。

至于功能测试,这正是您在文章中所谈论的内容,您想看的是 WebTestCase 类,它由the LiipFunctionalTestBundle bundle 很好地补充了更高级的案例。

这允许像testing a contact form that sends an email 的这个例子这样的事情,其中​​整个 HTTP 请求都在进程中完成,因为框架被编写为允许每个进程有多个请求并且没有全局状态,这很好用并且不会需要运行 http 服务器或其他任何东西。正如你所看到的,我也对响应的 HTTP 状态代码进行了断言,并且能够在不发送电子邮件的情况下捕获电子邮件,因为在 Symfony2 的标准发行版中的测试配置 sending of emails is disabled 中。

话虽如此,您也可以只使用 Symfony2 的 HttpFoundation 组件中的 Request 和 Response 类。它应该允许您测试您的代码,但是如果您使用整个框架,IMO 将无法获得尽可能多的好功能。当然这只是我的偏见;)

【讨论】:

【参考方案2】:

我建议下载 Symfony 2 框架路由组件:https://github.com/symfony/Routing

可在此处找到文档:http://symfony.com/doc/current/book/routing.html

也许它不能满足你的所有要求,但它是最接近的。

【讨论】:

【参考方案3】:

如果您熟悉 symfony(我认为您是),您应该查看 silex 在他们的网站上,这就是他们所说的: 微框架为构建简单的单文件应用程序提供了勇气。 Silex 的目标是:

简洁:Silex 展示了一个直观的 和简洁的 API,使用起来很有趣。 可扩展:Silex 有一个扩展 基于 Pimple micro 的系统 使它变得均匀的服务容器 更容易与第三方绑定 图书馆。 可测试:Silex 使用 Symfony2 抽象的 HttpKernel 请求和响应。这使它 非常容易测试应用程序和 框架本身。它也尊重 HTTP 规范并鼓励 正确使用。

【讨论】:

【参考方案4】:

我会添加Net_URL_Mapper,但它没有断言。这就是你排除它的原因吗?

另一个非常有趣的事情是silex。它还带有控制器测试。我会在 Symfony2 上使用它。但这是我个人的喜好。

【讨论】:

【参考方案5】:

很容易理解的愿望清单。我认为我们都讨厌在测试中遇到使测试变得混乱的依赖关系。测试应该简单而简短,在运行每个测试之前和之后要解决很多事情可能是一种负担。

从您的问题描述看来,您非常清楚自己在寻找什么。

我的第一反应是您为此使用 PHPUnit。它并不符合您的所有要求,但它是您可以建立的基础。它具有高度的可扩展性和灵活性,但它不支持 PSR-0,但它有自己的自动加载器,所以可能不会那么重。

根据您在问题中提供的信息,我不确定您的测试套件的设计或应用程序的设计是否会阻碍您编写和执行您希望进行的测试。

我闻起来可能两者都有。如果您的应用程序代码不易测试,那么 PHPUnit 之类的测试框架就无能为力了。例如,如果您的控制器不使用带有接口的请求对象,那么注入一些不是由 HTTP 请求而是由您的测试触发的请求就不是那么容易了。由于 HTTP 通常是 Web 应用程序的入口点,因此在此处进行抽象测试是值得的。除了特定框架之外,还有一些建议:Fig/Http。然而这只是一个指针。

与您提供的数据库方案类似:如果您的应用程序代码依赖于数据库,那么您的测试也将如此。如果您不想一直针对您的数据库进行测试,您需要让您的控制器能够在没有具体数据库的情况下工作。这与 HTTP 请求相当。

有很多方法可以应对这些情况,但是当我读到您的问题时,您看起来并没有没有受过教育,但您更多的是在寻找比现有解决方案更好的解决方案。

与每个自己的代码一样,很难找到与自己的设计相匹配的东西。我能给出的最好建议是扩展 PHPUnit 以添加您的应用程序所需的套件和约束同时您使用自动化测试的支持来重构您的应用程序以满足您的需求测试。

因此,您可以从测试开始,然后根据需要开发控制器。这将使您的控制器保持轻便,并帮助您找到所需的解决方案。

如果您发现 PHPUnit 缺少某些东西,您可以先自行扩展它,另外作者在添加缺少的功能方面非常有帮助。

请记住,如果不存在您需要的内容,您需要自己编写代码。但是,如果您能够与他人分享(部分)工作,那么您通常会比独自完成所有事情获得好处。这是现有框架的重点,无论是用于测试还是应用程序。

因此,如果到目前为止还没有这样的控制器/MVC 支持开箱即用的简单单元测试,可以满足您的需求,请加入并开发一种 TDD 方式。如果做得好,它可以完全符合您的要求。但是,我认为您并不孤单。所以不是一个非常具体的答案,但我只能说我在 PHPUnit 及其可扩展性方面取得了非常好的经验。这包括您在问题中提到的输出测试。

最后可能有一点区别:测试代码单元是一回事,测试它们是否在应用程序中与各种请求协同工作是另一回事。最后一个通常需要更大的测试设置。但是,如果您可以将单元彼此分开并明确定义它们与哪些其他单元交互,那么您通常只需要测试可以减少设置的单元之间的交互。这不会使您免于基础设施问题,但通常不会使用单元测试对其进行测试(尽管您可以扩展 PHPUnit 以执行其他类型的检查)。

一个流行的框架——即使是糟糕的设计——也有一个很大的优势,那就是组件往往会通过使用得到更好的测试。这通常会帮助您度过应用程序的最初几年,直到框架中的设计问题使您需要重写整个代码库(可能)。

由于控制器通常位于所有事物的中间,这可能会导致您倾向于测试整个应用程序而只想测试控制器的情况。所以你应该考虑控制器的设计和角色以及它们在整个应用程序中的位置,你真正想用你的控制器测试什么,这样你就可以真正根据你的需要使它们可测试。如果您不需要测试数据库,则不需要测试模型。所以你可以模拟一个返回随机数据的模型,把它发挥到极致。但是如果你想测试 HTTP 处理是否正确,那么可能首先需要一个抽象 HTTP 处理的单元。每个依赖于此的控制器都不需要进行测试(理论上),因为 HTTP 处理已经过测试。这也是抽象级别的问题。没有整体的解决方案,只是框架可以提供一些东西,但你会被框架所期望的那些范式所束缚。 php 中的 AFAIK 测试越来越流行,但这并不意味着现有框架对它有很好的支持。我从 zend 框架中知道,他们正在努力改善这种情况。因此,可能值得研究更流行的框架的最新发展,以了解这也会导致什么。

对于非常具体的问题,您需要始终自行测试。

选择 PHPUnit 并拥有自己的测试用例对我来说确实是一种实用的方式。根据您在 TDD 中的项目的需要对控制器进行编码,您应该会得到所需的内容。

Symfony 2 的更多基于组件的方法可能比 Zend Framework 更适合您的需求。但是,由于应用程序设计中的需求差异很大,我不能向您提出任何具体建议。对于一个应用程序来说,快速而可靠的解决方案是另一个应用程序的负担。见Page Controller。

【讨论】:

最后一段应该被标记为“TLDR”-section。 是的,更多的是评论而不是答案。文字墙下午;)【参考方案6】:

你可以看看http://ezcomponents.org/女巫正在变成apache zeta

有三种方法可以使 eZ 组件在您的 PHP 环境中可用,请在继续实际部分之前阅读本文的全文:

Use PEAR Installer for convenient installation via command line
Download eZ components packaged in an archive
Get the latest sources from SVN

我还没有动手,但看起来是个不错的解决方案...

【讨论】:

【参考方案7】:

Seldaek:WebTestCase 不太合适 - 它用于直接测试视图,而仅用于间接测试控制器或模型。

控制器的单元测试用例会调用控制器,可能会给它一个模板引擎的模拟对象(例如一个模拟 Smarty 对象),然后检查分配给该对象以进行显示的值:例如,如果您为 /countries/south-sudan 调用了控制器,您可以检查模板变量 $continent 是否设置为“Africa”。在大多数情况下,这种单元测试实际上不会涉及任何模板渲染。

【讨论】:

以上是关于支持单元测试的 PHP 前端控制器库的主要内容,如果未能解决你的问题,请参考以下文章

web前端好帮手 - Jest单元测试工具

前端测试框架学习

如何制作前端 Gallery.view 代码点火器

前端单元测试笔记 —— 覆盖率篇

使用jasmine来对js进行单元测试

php 获得前端控制器