单元测试Zend Controller并模拟一些执行的操作

Joh*_*yal 5 php phpunit zend-framework mocking

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

我知道我需要嘲笑这些但不清楚如何做到这一点.采用以下示例控制器(为清晰起见,减少):

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

}

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

实际上需要在这里嘲笑什么?竞争模型,数据库适配器,或模型工厂,还是全部三个?我该如何注射这些?我试过了(为了简洁而再次减少):

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);
}
Run Code Online (Sandbox Code Playgroud)

}

据我所知,PHPUnit奇怪地用mocks替换了对原始文件的任何引用,这样当调用dispatch时,就会使用伪模拟代替它们.这不会发生.有人可以澄清一下如何实现这一目标吗?

Goh*_*n67 4

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

这里发生的情况是,您需要使方法 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();    
}
Run Code Online (Sandbox Code Playgroud)