Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing constructor args in phpunit

We use Varien_Http_Client to make http requests from a Magento extension, like this:

public function callApi(…)
{
    <SNIP>

    // Set default factory adapter to socket in case curl isn't installed.
    $client = new Varien_Http_Client($apiUri, array(
        'adapter' => 'Zend_Http_Client_Adapter_Socket',
        'timeout' => $timeout, 
    ));
    $client->setRawData($xmlDoc->saveXML())->setEncType('text/xml');
    $response = $client->request($method);
    $results = '';
    if ($response->isSuccessful()) {
        $results = $response->getBody();
    }
    return $results;
}

I understand I should avoid testing the internals of Varien_Http_Client; rather, I should test that we are sending it the right inputs, and handling its outputs correctly. I can mock Varien_Http_Client easily enough, but even if I refactor this code to let me replace the Varien_Http_Client with its mock, I don't understand how to generally* test that the constructor was called with the expected arguments, since the constructor is called by PHPUnit::getMock.

I don't need a mock object; I need a mock class. How can I test that a constructor was called with expected arguments?

* (In this case I know ways to work around this problem specific to Varien_Http_Client, but what can I do with more opaque third-party code?)

like image 288
kojiro Avatar asked Oct 04 '22 16:10

kojiro


1 Answers

This is what we call "untestable" code. When you build dependencies inside your methods, there is no way to mock them. Every use of "new" keyword in your model is a signal that you should consider injecting the object instead of create it inside. In my opinion, the only exception from that rule is when you create a "data container" object or factory class. But in these cases probably you can test the object because methods will return it.

So as you said, the method you showed need a little refactor, for example:

class ApiClass
{
    protected $client;

    public function __construct(Varien_Http_Client $client)
    {
        $this->client = $client;
    }

    public function callApi()
    {
        $this->client->setRawData($xmlDoc->saveXML())->setEncType('text/xml');

        (...)

Best!

like image 76
Cyprian Avatar answered Oct 10 '22 01:10

Cyprian