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

发布于 2024-11-14 06:59:42 字数 2193 浏览 1 评论 0 原文

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

要求

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

后台

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

该应用程序已经有单元测试,但基于 HTTP 请求,这使得它们很慢。此外,当前在 www 目录中包含数十个 .php 文件的旧方法并不是最易于管理的解决方案,这就是为什么需要引入适当的控制器类。总共大约有20-30个控制器。

以前的经验

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

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

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

我不想要的

StackOverflow 有百万个“什么是最好的 PHP 框架”问题 (12345),但我不是在寻找那些,而是在寻找有助于控制器的特定库。如果它是模块化框架的一部分,那就太好了。

我也知道 PHP 框架比较网站,但它无助于回答我的问题,因为我的要求不是列在那里。

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

相关问题

I am looking for a (small) library that helps me cleanly implement a front controller for my pet project and dispatches requests to single controller classes. The front controller/dispatcher and controller classes need to be fully unittestable without sending HTTP requests.

Requirements

  • PSR-0 compatible
  • installable via its own PEAR channel
  • support for unit testing:
    • checking if the correct HTTP headers are sent
    • catches output to allow inspection in unit tests
    • perferably PHPUnit helper methods to help inspecting the output (for different output types, i.e. HTML, XML, JSON)
    • allows setting of incoming HTTP headers, GET and POST parameters and cookies without actually doing HTTP requests
  • needs to be usable standalone - without the db abstraction, templating and so that the fat frameworks all provide

Background

SemanticScuttle, the application that is bound to get proper "C" support, is an existing, working application. The library needs to blend in it and needs to work with the existing structure and classes. I won't rewrite it to match a framework's specific required directory layout.

The application already has unittests, but based on HTTP requests which make them slow. Also, the current old way of having several dozens of .php files in the www directory isn't the most managable solution, which is why proper controller classes need to be introduced. All in all, there will be about 20-30 controllers.

Previous experience

In general, I was pretty happy with Zend Framework for some previous projects but it has several drawbacks:

  • not pear-installable, so I cannot use it as dependency in my pear-installble applications
  • only available as one fat download, so I manually need to extract the required bits from it - for each single ZF update.
  • while unit test support exists for ZF controllers, it's lacking some advanced utility functionality like assertions for json, HTTP status code and content type checks.

While these points seem to be nit-picking, they are important for me. If I have to implement them myself, I do not need to use an external libary but write my own.

What I don't want

StackOverflow has a million "what's the best PHP framework" questions (1, 2, 3, 4, 5), but I'm not looking for those but for a specific library that helps with controllers. If it's part of a modular framework, fine.

I also know the PHP framework comparison website, but it doesn't help answer my question since my requirements are not listed there.

And I know that I can build this all on my own and invent another microframework. But why? There are so many of them already, and one just has to have all that I need.

Related questions

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

甜心小果奶 2024-11-21 06:59:42

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

至于功能测试,这实际上是您在文章中讨论的内容,您想要查看的是 WebTestCase 类,它由 LiipFunctionalTestBundle 包适用于更高级的情况。

这允许进行一些操作,例如测试发送电子邮件的联系表单示例,其中整个 HTTP 请求是在进程中完成的,因为框架被编写为允许每个进程多个请求并且没有全局状态,所以这工作得很好并且不需要运行 http 服务器或任何东西。正如您所看到的,我也对响应的 HTTP 状态代码进行了断言,并且能够捕获电子邮件而不发送它,因为在测试配置 在 Symfony2 标准发行版中禁用发送电子邮件

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

Knowing Symfony2 well, I can assure you it's definitely possible to use it just for the "C" in MVC. The models and templates are completely free and are typically executed from the Controllers anyway, so if you don't call Doctrine or Twig specifically, you can do what you want.

As for functional testing, which is really what you're talking about in your article, what you want to look at is the WebTestCase class, which is well complemented by the LiipFunctionalTestBundle bundle for more advanced cases.

That allows for some things like this example of testing a contact form that sends an email, where the entire HTTP request is done in process, since the framework is written to allow multiple requests per process and has no global state, this works very well and does not require a http server to be running or anything. As you can see I do assertions on the HTTP status code of the response too, and was able to capture the email without sending it since in test configuration sending of emails is disabled in the standard distro of Symfony2.

That being said, you could also just use the Request and Response classes from Symfony2's HttpFoundation component. It should allow you to test your code, but IMO you wouldn't get as many nice features as you could if you'd use the entire framework. Of course that's just my biased opinion ;)

故人爱我别走 2024-11-21 06:59:42

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

文档可以在这里找到: http://symfony.com/doc/current/book/routing.html

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

I would recommend downloading the Symfony 2 framework Routing component: https://github.com/symfony/Routing

Documentation is found here: http://symfony.com/doc/current/book/routing.html

Perhaps it does not satisfy all you requirements, but it's the closest.

甩你一脸翔 2024-11-21 06:59:42

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

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

If you are familiar with symfony (which I think you are) you should check out silex From their website this is what they say about it:
A microframework provides the guts for building simple single-file apps. Silex aims to be:

  • Concise: Silex exposes an intuitive
    and concise API that is fun to use.
  • Extensible: Silex has an extension
    system based around the Pimple micro
    service-container that makes it even
    easier to tie in third party
    libraries.
  • Testable: Silex uses
    Symfony2's HttpKernel which abstracts
    request and response. This makes it
    very easy to test apps and the
    framework itself. It also respects
    the HTTP specification and encourages
    its proper use.
爱她像谁 2024-11-21 06:59:42

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

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

I'd add Net_URL_Mapper, it doesn't have the assertions though. Is that why you ruled it out?

Another pretty interesting thing is silex. It also comes with controller tests. I'd use that over Symfony2. But that's my personal preference.

残龙傲雪 2024-11-21 06:59:42

一个非常可以理解的愿望清单。我认为当我们遇到使测试变得严重的依赖项时,我们都讨厌在测试中这样做。测试应该简单而简短,在运行每个测试之前和之后要解决很多事情可能会成为一种负担。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

对于具体细节,您始终需要自己进行测试。

然而,选择 PHPUnit 和自己的测试用例对我来说确实是一种实用的方法。根据 TDD 项目的需要对控制器进行编码,您应该会得到您需要的东西。

可能 Symfony 2 的更多基于组件的方法比您所经历的更适合您的需求Zend 框架。但是,我无法向您提供任何具体建议,因为应用程序设计中的需求差异很大。对于一种应用来说快速而可靠的解决方案对于另一种应用来说却是一种负担。请参阅页面控制器

Quite a understandable wishlist. I think we all hate it in testing when we run into dependencies that make testing to havoc. Tests should be simple and short, having many things to solve before and after running each test can be a burden.

From the description of your question it looks like that you pretty specifically know what you're looking for.

My first reaction would be that you use PHPUnit for this. It does not qualify all your requirements, but it's a base you can build on. It's highly expendable and flexible, however it does not support PSR-0 but has an autoloader of it's own so probably that does not weight that hard.

From the information you give in your question I'm not sure if the design of your testsuite(s) or the design of your application are hindering in writing and performing the tests you would love to.

I smell sort of probably both. If your application code is not easily testable, then there is not much a testing framework like PHPUnit can do about. So for example, if your controllers do not use a request object with an interface, it's not so easy to inject some request that was not triggered by the HTTP request, but by your tests. As HTTP is most often the entry-point into a webapplication, it pays to abstract here for tests. There exist some suggestions apart from specific frameworks: Fig/Http. However this is just a pointer.

Similar is this with the database scenario you give: If your application code is depending on the database, then your tests will be as well. If you don't want to test against your database all the time, you need to have your controllers being able to work w/o the concrete database. This is comparable with the HTTP requests.

There exists numerous approaches to cope with these circumstances, but as I read you question you don't look uneducated, but it's more you're looking for a better solution than exisiting ones.

As with every own code, it's pretty hard to find something that matches the own design. The best suggestion I can give is to extend PHPUnit to add those suites and constraints you need to for your application while you use the support of automated tests to refactor your application to fit the needs of how you would like to test.

So you can start with the tests and then develop the controller like you need it. This will keep your controller light I assume and help you to find the solutions you need.

If you find something that is missing with PHPUnit, you can first extend it on your own and additionally the author is very helpful in adding missing features.

Keep in mind that if there does not exist what you need, you need to code it your own. However if you're able to share (part) of the work with others, you most often get a benefit than by doing everything alone. That's a point for an existing framework, be it for testing or the application.

So if as of yet there is no such controller / MVC that does support easy unit-testing out of the box that fits your needs, chime in and develop one TDD-wise. If done right it can exactly match your requirements. However I think you're not alone with this problem. So not a very concrete answer, but I can only say that I made very good experiences with PHPUnit and it's extendability. That includes output tests you're mentioning in your question.

And probably a little differentiation at the end: It's one thing to test code-units and another to test if they all work in concert in the application with it's various requests. The last most often requires larger test setups by nature. However, if you can separate units from each other and clearly define with which other units they interact, then you normally only need to test the interaction between those which can reduce the setup. This does not save you from infrastructure problems, but those are normally not tested with unit-tests anyway (albeit you can extend PHPUnit to perform other type of checks).

A popular framework - even with a bad design - has the big plus that components tend to be better tested by use. That normally helps to go over the first years of your application until design issues in a framework make you need to rewrite your whole code base (probably).

As controllers often are sort in the middle of everything, this can lead to the scenario that you tend to test the whole application while you only want to test the controller(s). So you should think about the design and role of the controllers and their place within the overall application, what you really want to test with your controllers, so you can really make them testable according to your needs. If you don't need to test the database, you don't need to test the models. So you could mock a model returning random data to take it to the extreme. But if you want to test if HTTP handling is right, then probably a unit that abstracts HTTP handling is needed at first. Each controller relying on this would not be needed to test (theoretically) as the HTTP processing has been tested already. It's a question of the level of abstraction as well. There is no overall solution, it's only that frameworks can offer something but you're then bound to those paradigms the framework expects. AFAIK testing in php is getting more and more popular but that doesn't mean that the existing frameworks have good support for it. I know from the zend framework that they are working on this to improve the situation since longer. So it's probably worth to look into the more recent developments in the more popular frameworks to what this leads to as well.

And for the very specifics, you need to test on your own always.

Opting to PHPUnit and own testcases however does look as a practically way to me. Code your controllers as you need them for your project in TDD and you should get what you need.

Probably the more component based approach of Symfony 2 is better fitting your needs than what you experienced with Zend Framework. However, I can not suggest you anything specific as needs highly differ within application design. What's a quick and solid solution for one application is a burden for the other. See Page Controller.

塔塔猫 2024-11-21 06:59:42

你可以看看 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

我还没有接触过它,但看起来是一个很好的解决方案...

You could take a look at the http://ezcomponents.org/ witch is becoming apache zeta

There are three ways how to make eZ components available for your PHP environment, please read the whole of this article before continuing with the practical part:

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

I haven't got my hands into it yet but looks like a good solution...

哎呦我呸! 2024-11-21 06:59:42

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

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

Seldaek: WebTestCase isn't quite the right thing - it's for testing a view directly, and a controller or model only indirectly.

A unit test case for a controller would invoke the controller, likely giving it a mock object for the templating engine (e.g. a mock Smarty object), then check the values that were assigned to that object for display: for example, if you invoked the controller for /countries/south-sudan, you could check that the template variable $continent was set to "Africa". This kind of unit testing wouldn't actually involve any template rendering in most cases.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文