Search code examples
phpunit-testingtestingphpspec

Stubbing a stateful object in PHPSpec (or any unit testing framework)


How would you go about stubbing a DTO that also contains some logic (which kind of makes it more than a DTO anyway)? Would you even stub it? Consider this simple example:

class Context
{
    /**
     * @var string
     */
    private $value;

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

    public function getValue()
    {
        return $this->value;
    }

    public function setValue($value)
    {
        $this->value = $value;
    }


    /*
     * Some logic that we assume belong here
     */

}


class Interpreter
{
    public function interpret(Context $context)
    {
        $current_context = $context->getValue();

        if(preg_match('/foo/', $current_context ))            
        {
            $context->setValue(str_replace('foo', 'bar', $current_context));

            $this->interpret();
        }

        return $context->getValue();
    }
}

Now, unit testing Interpreter in a PHPSpec fashion:

class InterpreterSpec 
{
    function it_does_something_cool_to_a_context_stub(Context $context)
    {
        $context->getValue()->shouldReturn('foo foo');

        $this->intepret($context)->shouldReturn("bar bar");
    }
}

Obviously this'd create an endless loop. How would you go about unit testing the Interpreter? I mean, if you just passed a "real" instance of Contextinto it, you'd rely on that objects behaviour, and it wouldn't really be a unit test.


Solution

  • Based on what I see in your code, I would not fake the context but work with a real one. As far as I can see it is a value object with only the getter and setter being accessed.

    class InterpreterSpec 
    {
        function it_does_something_cool_to_a_context_stub()
        {
            $context = new Context("foo foo");
    
            $this->intepret($context)->shouldReturn("bar bar");
        }
    }