Pregunta

He estado recibiendo en pruebas unitarias con Zend Framework. Me estoy acostumbrando a las otras cosas que ofrecer pero estoy teniendo dificultades para comprender Mock Objects.

En este ejemplo, yo estoy tratando de utilizar un objeto de burla de poner a prueba mi modelo.

<?php

class Twitter_Model_Twitter
{
    private $_twitter;

    /**
     * Make the options injectable.
     * __contruct($auth, $key)
     */
    public function __construct() 
    {
        $config      = new Zend_Config_Ini(APPLICATION_INI, APPLICATION_ENV);
        $key         = $config->encryption->salt;
        $iv_size     = mcrypt_get_iv_size(MCRYPT_XTEA, MCRYPT_MODE_ECB);
        $iv          = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $password    = mcrypt_decrypt(MCRYPT_XTEA, $key, $password, MCRYPT_MODE_ECB, $iv);

        $this->_twitter = new Zend_Service_Twitter($username, $password);
    }


    public function verifyCredentials()
    {
        return $this->_twitter->account->verifyCredentials();
    }

    public function friendsTimeline($params)
    {
        return $this->_twitter->status->friendsTimeline($params);
    }
}

Para mi prueba de unidad:

require_once ('../application/models/Twitter.php');
class Model_TwitterTest extends ControllerTestCase
{
    /**
     * @var Model_Twitter
     */
    protected $_twitter;

    public function testfriendsTimeline() 
    {
        $mockPosts = array('foo', 'bar');    

        //my understanding below is:
        //get a mock of Zend_Service_Twitter with the friendsTimeline method
        $twitterMock = $this->getMock('Zend_Service_Twitter', array('friendsTimeline'));
        /*
        line above will spit out an error:
        1) testfriendsTimeline(Model_TwitterTest)
        Missing argument 1 for Mock_Zend_Service_Twitter_9fe2aeaa::__construct(), called in 
        /Applications/MAMP/bin/php5/lib/php/PHPUnit/Framework/TestCase.php on line 672 and
        defined /htdocs/twitter/tests/application/models/TwitterTest.php:38
        */

        $twitterMock->expects($this->once())
              ->method('friendsTimeline')
              ->will($this->returnValue($mockPosts));

        $model = new Twitter_Model_Twitter();
        $model->setOption('twitter', $twitterMock);

        $posts = $model->friendsTimeline(array('count'=>20));
        $this->assertEquals($posts, $mockPosts);
    }
}

¿Cómo se podría probar el siguiente? 1) VerifyCredentials () 2) friendsTimeline ()

Gracias, Wenbert

¿Fue útil?

Solución

Voy a responder a esta pregunta. Creo que he hecho este trabajo gracias a Zomg de #zftalk.

Aquí está mi nueva Twitter Modelo:

<?php
//application/models/Twitter.php
class Twitter_Model_Twitter
{
    private $_twitter;
    private $_username;
    private $_password;

    public function __construct(array $options = null) 
    {        
        if (is_array($options)) {
            $this->setOptions($options);
            $this->_twitter = new Zend_Service_Twitter($this->_username, $this->_password);
        } else {
            $twitterAuth = new Zend_Session_Namespace('Twitter_Auth');
            $config      = new Zend_Config_Ini(APPLICATION_INI, APPLICATION_ENV);
            $key         = $config->encryption->salt;
            $iv_size     = mcrypt_get_iv_size(MCRYPT_XTEA, MCRYPT_MODE_ECB);
            $iv          = mcrypt_create_iv($iv_size, MCRYPT_RAND);
            $password    = mcrypt_decrypt(MCRYPT_XTEA, $key, $twitterAuth->password, MCRYPT_MODE_ECB, $iv);

            $username    = $twitterAuth->username;
            $this->_twitter = new Zend_Service_Twitter($username, $password);
        }
    }

    public function setOptions(array $options)
    {
        $methods = get_class_methods($this);
        foreach ($options as $key => $value) {
            $pieces = explode('_', $key);
            foreach($pieces AS $piece_key => $piece_value) {
                $pieces[$piece_key] = ucfirst($piece_value);
            }

            $name = implode('',$pieces);
            $method = 'set' . $name;
            //$method = 'set' . ucfirst($key);
            if (in_array($method, $methods)) {
                $this->$method($value);
            }
        }
        return $this;
    }

    //I added this method. So that I could "inject"/set the $_twitter obj
    public function setTwitter($obj)
    {
        $this->_twitter = $obj;
        return $this;
    }


    public function verifyCredentials()
    {
        return $this->_twitter->account->verifyCredentials();
    }

    public function friendsTimeline($params)
    {
        return $this->_twitter->status->friendsTimeline($params);
    }
    //in the real code, more will go here...
}

Y en mi prueba de unidad, tengo esto:

<?php
// tests/application/models/TwitterTest.php
require_once ('../application/models/Twitter.php');

class Model_TwitterTest extends ControllerTestCase
{
    public function testVerifyCredentials() 
    {
        $stub = $this->getMock('Zend_Service_Twitter', array('verifyCredentials'),array(),'',FALSE);
        //FALSE is actually the 5th parameter to flag getMock not to call the main class. See Docs for this.
        //Now that I have set the $_twitter variable to use the mock, it will not call the main class - Zend_Rest_Client (i think)

        $stub->expects($this->once())
              ->method('verifyCredentials');

        $model = new Twitter_Model_Twitter();

        //this is the part where i set the $_twitter variable in my model to use the $stub
        $model->setOptions(array('twitter'=>$stub)); 

        $model->verifyCredentials();
    }
}

De todas formas, creo que tengo trabajo.

1) La prueba de la unidad ya no trató de conectarse a twitter.com:80

2) Después de conseguir los setOptions () que trabajan en el Twitter_Model, $ Modelo-> VerifyCredentials () en mi unidad de prueba fue llamado con éxito.

Voy a esperar a que otros en Stackoverflow confirmar que es la respuesta correcta. Por tanto, le gustaría saber de ustedes.

Gracias !!!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top