【问题标题】:Unit Testing Zend Controller and Mocking some of the performed actions单元测试 Zend 控制器和模拟一些已执行的操作
【发布时间】:2012-04-13 07:46:51
【问题描述】:

我正在为我的控制器编写一些单元测试 (PHPUnit 3.6),并希望验证正确的操作等正在被触发。这很容易。然而,一些控制器还通过不希望的模型执行某些操作,例如将记录插入数据库。

我知道我需要模拟这些,但不清楚如何做到这一点。以下面的示例控制器为例(为了清楚起见,删减了):

public function addAction()
{
    $data = $this->getRequest()->getPost();
    $model = $this->getModelFactory()->getCompetitionModel()->insert($data);    }

}

注意,我要做的只是验证正确的控制器和动作是否已被调度,但不希望实际插入记录。同样,我有删除等的等价物。我不希望实际删除记录。

这里实际上需要嘲笑什么?竞争模型、数据库适配器、模型工厂,还是三者兼而有之?我该如何注射这些?我已经尝试过(再次为简洁起见):

public function testAddActionIsDispatched()
{
    $this->request->setMethod('POST');
    $this->request->setPost(array($data…));

            $modelMock = $this->getMockBuilder('Competition_Adder')
                 ->disableOriginalConstructor()
                 ->getMock();                


            $factoryMock = $this->getMockBuilder('ModelFactory')
                    ->disableOriginalConstructor()
                    ->getMock(); 

        // Configure the stub.
            $factoryMock->expects($this->any())
                ->method('getCompetitionModel')
                ->will($this->returnValue($modelMock));        

            $modelMock->expects($this->once())
                    ->method('insert')
                    ->will($this->returnValue(true));

            $this->dispatch('/mymodule/add/');
            $this->assertController('test');
            $this->assertAction('add');  
            $this->assertResponseCode(200);
}

}

我的理解是 PHPUnit 神奇地用模拟替换了对原始的任何引用,以便在调用调度时使用假模拟代替它们。这不会发生。有人可以澄清这是如何实现的吗?

【问题讨论】:

    标签: php zend-framework mocking phpunit


    【解决方案1】:

    看起来您的模拟设置正确。在我看到你的问题并进行了一些研究之前,我实际上并不知道你可以从模拟中返回模拟。

    这里发生的情况是,您需要让 getModelFactory() 方法返回模拟工厂的实例。现在它只是返回真实的东西。

    我不确定您的 getModelFactory 方法会发生什么,所以我很难说您可以如何覆盖它以使其返回您的模拟工厂。

    但也许你不必重写它。在我的 ZF 应用程序中,我不测试控制器,但为了测试需要将内容保存到我的模型的内容,我只需在配置文件中更改为测试数据库进行测试。我使用 Doctrine1.2,所以我只是在 setUp() 方法中启动一个事务,并在 tearDown 方法() 中进行回滚。

    我的测试数据库完全是空的,我基本上用一些测试特定的工厂类在每个测试方法中创建必要的数据。缺点是它似乎确实使用了大量内存。我认为它在大约 140 次测试中达到了 200MB,而且并非所有这些测试都需要访问数据库。

    我只使用这种方法,因为它对我来说是最容易实现的,因为我只需要更改数据库配置。如果你不是在做一个非常大规模的项目,这可能对你有用。您还可以使用内存中的 sqlite 对测试数据库运行测试,这应该对您有用,因为没有在测试中测试数据库。数据刚刚被插入,然后在测试结束时,它就消失了。在我的项目中,我使用 MySQL 测试数据库,因为我希望它尽可能接近生产环境。

    示例(您可能没有使用 Doctrine。我只是在说明如何使用事务和回滚来使测试数据库保持一致状态):

    public function setUp()
    {
        $this->bootstrap = new Zend_Application(
            APPLICATION_ENV, APPLICATION_CONFIG);       
        parent::setUp();
        $bootstrap = $this->bootstrap->getBootstrap();
    
        $this->_conn = Doctrine_Manager::connection();
        $this->_conn->beginTransaction();
    }
    
    public function tearDown()
    {
        $this->_conn->rollback();        
        $this->_conn->close();    
    }
    

    【讨论】:

    • 谢谢,是的,基本上我使用配置模拟了工厂,因此单元测试没有使用真实的东西。
    【解决方案2】:

    是的,请查看上一个答案。在所有情况下我都同意。但是同样的事情不能用 MySQL 和 Zend_Db 来实现。那是因为 Zend_Db 没有嵌套事务。 所以你唯一能做的就是使用测试数据库并在每次测试后重建它。

    查看how it is done via Codeception testing framework with Zend Framework and Db module

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-08-01
      • 1970-01-01
      • 2012-02-27
      • 2017-02-22
      • 2011-11-23
      • 1970-01-01
      • 2014-07-30
      相关资源
      最近更新 更多