Testing CURL wrapper

Discussion of testing theory and practice, including methodologies (such as TDD, BDD, DDD, Agile, XP) and software - anything to do with testing goes here. (Formerly "The Testing Side of Development")

Moderator: General Moderators

Post Reply
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Testing CURL wrapper

Post by Ambush Commander »

I'm wondering how I would unit test this:

Code: Select all

<?php

/**
 * Object-oriented wrapper for CURL, see http://php.net/manual/en/ref.curl.php
 */
class CURL
{
    public $handle;
    
    // basic constructs
    public function __construct() {
        $this->handle = curl_init();
    }
    public function __clone() {
        $this->handle = curl_copy_handle($this->handle);
    }
    
    // baton methods
    public function setopt($option, $value) {
        return curl_setopt($this->handle, $option, $value);
    }
    public function setoptArray($options) {
        return curl_setopt_array($this->handle, $options);
    }
    public function exec() {
        return curl_exec($this->handle);
    }
    
    // convenience methods
    
    /**
     * Downloads a URL to a string, or a file if specified
     * @param $url string URL to download
     * @param $filename string Filename to download to, download is returned
     *          if not set.
     * @return String download result, or handle to created file
     */
    public function download($url, $filename = false) {
        $this->setopt(CURLOPT_URL, $url);
        $fh = false;
        if ($filename) {
            $fh = fopen($filename, 'w');
            $this->setopt(CURLOPT_FILE, $fh);
        } else {
            $this->setopt(CURLOPT_RETURNTRANSFER, true);
        }
        $result = $this->exec();
        if ($fh) return $fh;
        else return $result;
    }
    
}
I suppose I could use partial mocks to handle the download() function, but it'd be laborious and wouldn't cover all of the classes' functionality. Another would be to pass CURL a URL using a stream wrapper, which would remove the overhead of an HTTP call. Any other ideas?
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

There are some things that just don't lend themselves to unit testing.... like this. A system test would work where you connect to a resource you know exists purely for testing purposes. Portability becomes an issue with these sorts of tests though.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

I went with that. Should be reasonably portable. For the curious, this is what I did:

Code: Select all

<?php

/**
 * @requires CURLTest.txt with contents 'CURLTest.txt contents'
 */
class CURLTest extends UnitTestCase
{
    
    function getURL() {
        return 'file:' . dirname(__FILE__) . '\CURLTest.txt';
    }
    
    function getURLContents() {
        return 'CURLTest.txt contents';
    }
    
    function getTempFilename() {
        $tmp_file = tempnam($_ENV['TMP'], 'CURLTest');
        if (file_exists($tmp_file)) unlink($tmp_file); // sanity check, highly unlikely
        return $tmp_file;
    }
    
    function test_download_urlByConstructorAndNoFile() {
        $curl = new CURL($this->getURL());
        $result = $curl->download();
        $this->assertIdentical($result, $this->getURLContents());
    }
    
    function test_download_urlByParamAndNoFile() {
        $curl = new CURL();
        $result = $curl->download($this->getURL());
        $this->assertIdentical($result, $this->getURLContents());
    }
    
    function test_download_urlByParamAndFile() {
        $tmp_file = $this->getTempFilename();
        $curl = new CURL();
        $result = $curl->download($this->getURL(), $tmp_file);
        
        $this->assertTrue(is_resource($result), 'Expected result is resource');
        $this->assertIdentical(fread($result, 8192), $this->getURLContents());
        $this->assertFalse(fread($result, 8192), 'Expected unable to read resource');
        fclose($result); // must be done before file_get_contents test
        
        $this->assertIdentical(file_get_contents($tmp_file), $this->getURLContents());
        unlink($tmp_file);
    }
    
}
Post Reply