在Zend Framework应用程序中使用PHPUnit进行存根和模拟(Stubbing & mocking in PHPUnit in a Zend Framework application)

我是Zend Framework和PHPUnit的新手。 我正在将遗留应用程序转换为MVC体系结构,并试图编写单元测试。 我对单元测试的概念有点熟悉,但总体上我被困在一些残留和嘲弄之中。 例如考虑以下内容

在控制器操作中,我试图测试我传入的成员ID。 然后我使用这个ID初始化一个成员对象。 然后我调用一些与成员对象关联的方法,并将返回值分配给视图对象。

class A extends Zend_Controller_Action { public function viewAction() { $member = new Member($this->getRequest()-> getParam('id')); //perform various calls on the member object $gender = $member->getGender(); ... //assign the return values to the view object $this->view->assign('gender',$gender); ... } }

如何在我的测试中模拟$ member变量,以便我可以自定义方法的返回值?

如果我的理解不正确,我将不胜感激一些指导。

谢谢!

I am new to the Zend Framework and PHPUnit. I am transforming a legacy application to a MVC architecture and am trying to write unit tests. I am somewhat familiar with unit testing concepts but am stuck with stubbing and mocking in general. For instance consider the following

In a controller action I am trying to test I pass in a member ID. I then initialize a member object using the ID. Then I call a number of methods associated with the member object and assign the return values to the view objects.

class A extends Zend_Controller_Action { public function viewAction() { $member = new Member($this->getRequest()-> getParam('id')); //perform various calls on the member object $gender = $member->getGender(); ... //assign the return values to the view object $this->view->assign('gender',$gender); ... } }

How do I mock the $member variable in my tests so that I can customize the methods return values?

If my understanding here is incorrect I would greatly appreciate some guidance.

Thank you!

最满意答案

如果我正确理解你,你正在为这个动作写一个测试。 在这种情况下,不可能模拟$ member,因为新实例是在方法内创建的。 这就是为什么我们都尽力将尽可能多的new语句尽可能多地放在对象图中(DI)。

通常有一个特殊的PHPunit测试用例Zend_Test_PHPUnit来测试你的控制器。

但事实上,正确测试ZF控制器是非常困难甚至是不可能的(意思是完全隔离)。 您最好测试应用程序的其余部分,通用库等。

换句话说,在ZF1逻辑中,控制器是中央布线位置(引导之后),传统上使用了许多new语句。 显然,这会导致不可测试性,因为每个创建而不是注入的实例都是不可移植的。

正如@vascowhite指出的那样,争取精益控制器通常也不错。 这意味着将尽可能多的逻辑移动到模型层。 这将导致更少的冗余(DRY)和更好的可测试性。

但要注意不要让你的模型膨胀。 有时,您可能希望将一些代码考虑到其他组件中。

另一个问题是你不能模拟前端控制器,因为它是一个单身人士。 所以你实在没有太多的选择来测试这样的行为。 唯一的选择是注入成员实例或从注册表中获取它(也不是一个好主意)。

所以,考虑到很明显,你无法完全隔离你的动作测试。 但

不过,ZF2测试会更容易。

If I understand you correctly, you're writing a test for this action. In that case it's impossible to mock $member since the new instance is created inside the method. That's why we're all striving to float as many of our new statements as far up in the object graph as possible (DI).

Generally there is the special PHPunit testcase Zend_Test_PHPUnit to test your controllers.

But it is, as a matter of fact, very hard or even impossible to test ZF controllers correctly (meaning with full isolation). You'd be better of to test the rest of your app, your general library, etc.

In other words, in the ZF1 logic, the controller is the central wiring place (after the bootstrap), where a lot of new statements are traditionally used. Obviously that leads to non-testability because every instance which is created instead of injected, is unmockable.

As @vascowhite pointed out, it is also generally good to strive for lean controllers. This means, move as much logic as possible to your model layer. This will lead to less redundance (DRY) and better testability at the same time.

But pay attention not to bloat your models either. At one point you will probably want to factor some code out into additional components.

An additional problem is that you can't mock the Front Controller either since it's a singleton. So you really don't have many options to test such an action. The only option would be to inject the member instance or get it from the registry (not a good idea either).

So, given all that it is clear that you can't reach full isolation for your action tests. But

ZF2 will be much easier to test, though.

更多推荐