PHPUnit, treat our programmer better

While no doubt PHPUnit is an excellent project, today i was so frustrated because of it.

Look at the following code, first I declared an mock then defined some behavior of the mock.
Since I did some re-factoring and use CatetoryId instead of Category here, I renamed mock method from ‘getCategory’ to ‘getCategoryId’. Then when the getCategoryId is called in the test, it will not return 2, because this method is not declared. I didn’t notice it for a long time, and check all possibilities.

I’m totally fine with two steps workflow, i.e. First declare then define. But why there is no warning/error when I try to define a mock method, which is not declared.

$product = $this->getMock('Product', array('getId', 'getCategory', 'getPrice'));
$product = $this->expects($this->any())
->method('getCategoryId')
->will($this->returnValue(2));
view raw gistfile1.aw This Gist brought to you by GitHub.

Send complex json request

As using Backbone.js I wanted to send a whole JSON object to the back end, which is implemented with Zend Framework.

Tim White has written a very good article about it.

What I have done is converting the JSON object to a string and send it per POST to the back end. Then let back end decode this string.

The code of frontend is:

           $.ajax({
               url: '/controller1/action1/format/json',
               type: 'POST',
               data: JSON.stringify(data),
               contentType: 'application/json',
               success: function(resp) {cb(resp);},
               error: function(resp){errorCb(resp);}
            });

JSON.stringify is used here to serialize the JSON to string.

The backend code is like:

        $data = json_decode($this->getRequest()->getRawBody());

Since the string of json is send per post payload, you can not use

$this->getRequest()->getParams();

tail complains cannot watch `var/log/system.log’: No space left on device

Solution:
sudo sysctl fs.inotify.max_user_watches=999999999

edit
/etc/sysctl.conf
add
fs.inotify.max_user_watches=999999999

see http://unix.stackexchange.com/questions/13751/kernel-inotify-watch-limit-reached

Solve the problem about sending email per sendmail extremely slow

error message

    My unqualified host name (ting-Vostro-460) unknown; sleeping for retry


solution:

Adding your host name (my host name is ting-Vostro-460, replace it with your host name) into /etc/hosts like following

        127.0.0.1 localhost ting-Vostro-460 ting-Vostro-460.


The “.” after the host name is very important.

 

You may need to add the following line into /etc/mail/sendmail.mc your mail

FEATURE(`accept_unresolvable_domains')dnl
After changing the config using make to generate sendmail.cf. Then restart the sendmail >sudo /etc/init.d/sendmail restart.

Magento cache

If your/var/cache has not write right for www-data, magento will save the cache file into /tmp/magento/var/cache

install nltk on mac os lion

If you try to install nltk with easy_install you will get an error, setup.py can not be found. Using src file directly can solve this problem

➜ ~ sudo easy_install pyyaml

➜ ~ sudo easy_install http://pypi.python.org/packages/source/n/nltk/nltk-2.0.1rc1.tar.gz

clone an php object

Array and Object in PHP are all reference. If you assign a variable with an array or an object, this variable is a reference of that array/object. Using clone you can copy an object.


php> class a { public $name; public function __costruct($name) {$this->name = $name;}}

php> $a  = new a('wang');

php> $b = $a;

php> $b->name = 'ting';

php> var_dump($a);
object(a)#2 (1) {
  ["name"]=>
  string(4) "ting"
}

php> $c = clone $a;

php> var_dump($c);
object(a)#3 (1) {
  ["name"]=>
  string(4) "ting"
}

php> $c->name = 'jjj';

php> var_dump($a);
object(a)#2 (1) {
  ["name"]=>
  string(4) "ting"
}

php> var_dump($c);
object(a)#3 (1) {
  ["name"]=>
  string(3) "jjj"
}

php>

Zend Controller in Ajax Context Testing

We can use AjaxContext action helper to define a context of an action.

    public function init()
    {
        $ajaxContext = $this->_helper->getHelper('AjaxContext');
        $ajaxContext->addActionContext('get-zip-code', 'json')
                    ->initContext();
    }
    public function getZipCodeAction()
    {
        // that is all! you don't need to do any for json encode
        $this->view->zip = '123';
    }

Since we use AjaxContext then we don’t need to create a get-zip-code.phtml.
Till this step everything is fine.
Then I want to write a unit test for it.

class ZipControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
    public function setUp()
    {
        $this->bootstrap = new Zend_Application(
            APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini');
        parent::setUp();
    }

    /**
     * testICanGetZipCodeAsJsonString
     *
     * @return void
     * @group now
     */
    public function testICanGetHashForCheckingCredit()
    {
        $this->dispatch(
            '/checkout/payone/get-hash-for-checking-credit/format/json');
        $this->assertResponseCode(200);
        $this->assertEquals('{"zip":"123"}', $this->getResponse()->getBody());
    }
}

The second assertion fails. And using var_dump($this->getResponse()->getBody()) we can find out the layout is not disable. Why? Doesn’t AjaxContext work? After a little hacking the Zend_Controller_Action_Helper_AjaxContext I found the AjaxContext will chech the type of Request. It works just when the Request is a Xml Http Request.

In order let test to work, we have to forge the Request before dispatch it.


    /**
     * testICanGetZipCodeAsJsonString
     *
     * @return void
     * @group now
     */
    public function testICanGetHashForCheckingCredit()
    {
        // forge the request as an XMLHttpRequest!
        $this->getRequest()->setHeaders(array('X_REQUESTED_WITH' => 'XMLHttpRequest'));

        $this->dispatch(
            '/checkout/payone/get-hash-for-checking-credit/format/json');
        $this->assertResponseCode(200);
        $this->assertEquals('{"zip":"123"}', $this->getResponse()->getBody());
    }

Now the test working fine.

ruby using gems

Recently i tried to install vagrant on my ubuntu box and met some problem.
I know ruby very little, perhaps someone can explain there problem.

After installing vagrant by gem i can not run it directly, this is because vagrant is in /var/lib/gems/1.8/gems/vagrant-0.8.2/bin/vagrant which is not in my PATH. Ok link this file to /usr/bin which is in my path.

After that still vagrant can not be run. Error message shows vagrant lib can not be found. It seams that the ruby can not find vagrant.

Add require ‘rubygems’ before require ‘vagrant’ solves the problem.

These problems just happen in ubuntu, i have installed vagrant per gem on my imac, and there is no problem at all. Is gem for mac and for linux not the same?

js is weird