Symfony2最佳实践,业务逻辑和单元测试

时间:2015-03-23 07:53:19

标签: unit-testing symfony symfony-forms

我想通过单元测试创​​建一个高度可维护的代码。

我已经阅读了最佳实践,因此目录按照最佳实践进行组织,只有一个名为AppBundle的捆绑包,并且我使用了注释。

我遇到了业务逻辑问题。我读过我不应该把业务逻辑放在控制器中。由于绝大多数代码都不是要重用,我把逻辑放在控制器中。昨天我读了here"逻辑应该存在于控制器中,除非你要对它进行单元测试,或者直到你需要重新使用它为止#34;这让我晕了:如果把逻辑放在控制器里面,我不会进行单元测试吗?

我理解"控制器应该尽可能精简,几行代码就可以将各种东西粘在一起"但形式怎么样?表单通常有一个逻辑,如显示表单,如果它有效,则显示另一个页面"。现在,如果我要将表单创建和逻辑放在服务(或模型?)中,我必须将页面渲染命令放在其中,所以基本上控制器将是1行,所有服务中的其余部分,以及要显示哪个页面的实际决定将在服务内部完成,而不是控制器本身...那么控制器的重点是什么,只是路由?

在继续之前我真的需要理解这一点(我已经开发了3个月,而且我必须做很多工作,但现在比以前更好)...

谢谢!

编辑:一些额外的考虑因素,以解决以下一些评论。

我清楚地了解了表单在Symfony中的工作方式,创建表单以及使用" isValid()"在同一个地方。

让我们设想以下控制器执行以下操作:

get the current customer from security context
queries the DB to get the field $user->getIsBillable()
if the user is not billable
    queries the DB to find if someone else is paying for him
else //the user is billable
    create and manage form1
if the user is not billable but there is someone who is paying for him
    check if the license is active (I have to call an external API)
    if the license is not ok
        redirect to a page to update credit card info
if the user is not billable
    create and manage form2
else
    create and manage form3
render the license management page with all the necessary forms created  

该怎么办?将所有这些东西放入一个可以返回表单的服务中(如果没有创建表单,则为null)?考虑一下"是否有效"一些表单我使用简单的更新信息呈现相同的页面。或者我应该创建表单创建的服务foreach并将逻辑保留在控制器中?

4 个答案:

答案 0 :(得分:7)

您应该将逻辑保留在控制器之外,以便使代码更具可重用性,并减少代码重复。

最佳做法是将您的业务逻辑注册为Symfony服务。 控制器应尽可能精简,因为它只处理视图并访问服务以运行业务逻辑功能。

使用服务将使您的代码更具可重用性,并且为代码的每个部分编写单元测试会更容易。

在Symfony2中以不同的方式处理表单,您应该阅读更多相关内容:http://symfony.com/doc/current/book/forms.html

答案 1 :(得分:2)

与大多数php框架一样,symfony2也存在问题。

结果证明,symfony2最佳做法并不总是最佳做法。但在大多数情况下,symfony允许松散耦合和适当的依赖注入,它只是不会在“书”中告诉你。

例如,一个非常重要的主题:http://symfony.com/doc/current/cookbook/controller/service.html

我通常将我的表单类型作为服务,将控制器作为服务以及其他业务逻辑服务。理想情况下,我的控制器操作大约需要3-5行代码。有时在处理文件上传时,它们会稍长一些。

您可以对业务逻辑服务进行单元测试,但对于您的控制器和表单,您需要进行某种集成测试,或使用大量模拟。

据我所知,“Selenium”是测试此类内容的好工具,我还没有使用它。

答案 2 :(得分:1)

我想在其他答案中添加的一件事就是单元测试与功能测试不同。

单元测试

当您想要测试代码的单个“单元”时(例如类中的方法),您需要单元测试

功能测试

当您想要测试功能的“套件”时(如许多方法交互,数据库交互,Web服务等),您需要功能测试

小结

理想情况下,您希望为包含繁重业务逻辑的类编写单元测试,而您需要使用功能测试来测试整个控制器(因此页面将使用所有类交互和数据库交互进行渲染,页面为渲染,页面发布等等)

最好的方法,对我来说 - 这只是一个从今天开始尝试从新手的角度来理解测试的开发者的意见 - 是相互混合:单元测试(当然是隔离!)我我确信(简化)我提供给我的方法的每个输入都将返回正确的输出,而功能测试将帮助我测试整个事物和交互。

答案

所以,回到你的问题 - 似乎看起来似乎更广泛 - 一个好的方法是将所有业务逻辑保持在控制器之外(即使你确定[并且对我来说你永远不会确定] enaugh]你输入的代码将永远不会在其他地方重复使用)通过定义服务(如其他答案所述)。然后你将对你的服务进行一些单元测试,然后你可能需要一些功能测试来检查所有“胶水是否正确地保持在一起”。

我不知道我是否遗漏了某些东西(很可能)。为了更完整,我将attach我在Symfony2上的旧问题(当时我正在研究它和MVC模式)

答案 3 :(得分:0)

将代码构建为干净且易于维护是一件非常困难的事情,我建议您开始研究SOLID原则,而不是对MVC表面理解:

  1. Single Responsability Principle - SRP
  2. Open/Closed Principle - OCP
  3. Liskov Substitution - LSP
  4. Interface Segregation - ISP
  5. Dependency Inversion Principle - DIP