Loïc Faugeron Technical Blog

phpspec tip: don't mock SUT inputs 19/08/2024

Looking at some old code of mine, I've found the following test:

<?php

namespace spec\Memio\SpecGen\GenerateMethod;

use Memio\Model\File;
use Memio\Model\Method;
use Memio\Model\Objekt;
use Memio\SpecGen\GenerateMethod\GeneratedMethod;
use PhpSpec\Console\ConsoleIO;
use PhpSpec\ObjectBehavior;

class LogGeneratedMethodListenerSpec extends ObjectBehavior
{   
    function let(ConsoleIO $io)
    {
        $this->beConstructedWith($io);
    }

    function it_logs_the_generated_method(ConsoleIO $io, File $file, Method $method, Objekt $object)
    {
        $className = 'Vendor\Project\MyClass';
        $methodName = 'myMethod';
        $generatedMethod = new GeneratedMethod($file->getWrappedObject());
        $file->getStructure()->willReturn($object);
        $object->getName()->willReturn($className);
        $object->allMethods()->willReturn([$method]);
        $method->getName()->willReturn($methodName);

        $io->write(<<<OUTPUT

  <info>Generated <value>{$className}#{$methodName}</value></info>

 OUTPUT
        )->shouldBeCalled();

        $this->onGeneratedMethod($generatedMethod);
    }
}

And while reading it, one of the things that caught my attention was the setting up of mocks for SUT inputs (SUT means System Under Test, the class we're testing).

The purpose of this test is to specify how LogGeneratedMethodListener should behave, through its interactions with the ConsoleIO collaborator.

But here, it's also specifying how LogGeneratedMethodListener interacts with the input parameter GeneratedMethod.

GeneratedMethod encapsulates data relevant to the process of generating the code for a Method. It doesn't have any critical behaviour: we just call getters on it.

So my advice to you (me, from the past), would be to not bother creating Mocks for it:

<?php

namespace spec\Memio\SpecGen\GenerateMethod;

use Memio\Model\File;
use Memio\Model\Method;
use Memio\Model\Objekt;
use Memio\SpecGen\GenerateMethod\GeneratedMethod;
use PhpSpec\Console\ConsoleIO;
use PhpSpec\ObjectBehavior;

class LogGeneratedMethodListenerSpec extends ObjectBehavior
{   
    function let(ConsoleIO $io)
    {
        $this->beConstructedWith($io);
    }

    function it_logs_the_generated_method(ConsoleIO $io)
    {
        $className = 'Vendor\Project\MyClass';
        $methodName = 'myMethod';
        $generatedMethod = new GeneratedMethod((new File('src/MyClass.php'))
            ->setStructure((new Objekt($className))
                ->addMethod(new Method($methodName))
            )
        );

        $io->write(<<<OUTPUT

  <info>Generated <value>{$className}#{$methodName}</value></info>

 OUTPUT
        )->shouldBeCalled();

        $this->onGeneratedMethod($generatedMethod);
    }
}