Skip to content

Instantly share code, notes, and snippets.

@danscotton
Created February 20, 2014 18:46
Show Gist options
  • Save danscotton/9120521 to your computer and use it in GitHub Desktop.
Save danscotton/9120521 to your computer and use it in GitHub Desktop.
<?php
class Parser
{
public function parse($json = null)
{
return array_reduce($this->parseItems($json), array($this, 'parseItem'), new Collection());
}
private function parseItems($json)
{
switch (true) {
case $this->invalid($json):
throw new InvalidArgumentException('Expected JSON as first parameter to `parse` method.');
break;
case $this->unknown($json):
throw new ParserError('Expected JSON to have `results` key.');
break;
}
$results = json_decode($json, true);
return $results['results'];
}
private function parseItem($collection, $item)
{
$collection->add(new CreativeWork($item));
return $collection;
}
private function invalid($json)
{
return !is_string($json) || is_null(json_decode($json));
}
private function unknown($json)
{
return array_key_exists('results', json_decode($json, true)) ? false : true;
}
}
<?php
class ParserTest extends PHPUnit_Framework_TestCase
{
public function setup()
{
$this->parser = new Parser();
}
public function testParseCreatesCreativeWorkWithItem()
{
$item = array("@id" => "http://www.bbc.co.uk/things/1");
$response = $this->results($item);
$collection = $this->parser->parse($response);
// I need to verify the `CreativeWork` model was instantiated with `$item`.
// How can I mock any instance of `CreativeWork` and verify that its constructor was
// called with `$item`? I'm thinking along the lines of:
//
// $mock = Mockery::mock('CreativeWork')
// $mock->shouldBeCreatedWith($item) -> this is the verification..
}
private function results()
{
return json_encode(array('results' => func_get_args()));
}
}
@davedevelopment
Copy link

Right now, it's not possible. You can use the instance mocks, but they're messy as you need to run tests with process isolation, but even then, you can't yet verify how the constructor was called, though I don't think it would be too difficult to add.

If at all possible, I'd just be trying to verify the observable state changes, like

$this->assertEquals(1, $collection->count());
$this->assertInstanceOf("CreativeWork", $collection->first());
$this->assertEquals("http://www.bbc.co.uk/thinks/1", $collection->first()->getId());

@fedecarg
Copy link

fedecarg commented Mar 2, 2014

Hi Dan - you can use PHPUnit to verify that the CreativeWork model is instantiated with the right value. It doesn't really matter if you mock the model class or not, you can check before passing $item.

For example:

<?php

class CreativeWork
{
    private $item;

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

    public function getItem()
    {
        return $this->item;
    }
}

class Parser
{
    public function parse($json = null)
    {
        $collection = new ArrayObject();
        $items = $this->parseItems($json);
        return $this->parseItem($collection, $items[0]);
    }

    public function parseItems($json)
    {
        $results = json_decode($json, true);
        return $results['results'];
    }

    public function parseItem($collection, $item)
    {
        $collection->append(new CreativeWork($item));
        return $collection;
    }
}

class ParserTest extends PHPUnit_Framework_TestCase
{
    public function testParseCreatesCreativeWorkWithItem()
    {
        $item = array("@id" => "http://www.bbc.co.uk/things/1");

        $parser = $this->getMock('Parser', array('parseItem'));
        $parser->expects($this->any())
            ->method('parseItem')
            ->with($this->anything(), $this->anything())
            ->will($this->returnCallback(
                function() use ($item) {
                    $args = func_get_args();
                    // ... some code here ...
                    $args[0]->append(new CreativeWork($args[1])); // $args[1] === $item
                    return $args[0]; // return collection
                }
           ));

        $json = json_encode(array('results' => array($item)));
        $collection = $parser->parse($json);

        $this->assertTrue($collection->offsetGet(0) instanceof CreativeWork);
        $this->assertTrue($collection->offsetGet(0)->getItem() === $item);
    }
}

There are other ways to do this, but verifying the arguments using a callback function is the easiest way to do it.

Give me a shout if you have any questions, I'm on IRC: #news (Federico) and Twitter @fedecarg


Dave - good to see you buddy. Hope all is well :)

Cheers,
Federico

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment