laravel-5phpspec

phpSpec no beCalled([array:0]) matcher found for null


I'm trying to get into the workfow of using phpSpec to desing my classes. I have stumbled on testing a handle method on one of my event handlers.

My spec:

use App\Order;
use App\Models\Payments\Payment;
use App\Services\Payments\PaymentService;
use App\Events\Payments\AccountPayment;

class RecordPaymentTransactionSpec extends ObjectBehavior
{
    function let(PaymentService $paymentService)
    {
        $this->beConstructedWith($paymentService);
    }

    function it_is_initializable()
    {
        $this->shouldHaveType('App\Handlers\Events\Payments\RecordPaymentTransaction');
    }

    function it_should_record_payment_transaction(AccountPayment $event)
    {
        $this->paymentService->recordPayment($event)->shouldBeCalled();
    }
}

And this my implementation:

class RecordPaymentTransaction {

    public $paymentService;

    /**
     * Create the event handler.
     *
     * RecordPaymentTransaction constructor.
     * @param PaymentService $paymentService
     */
    public function __construct(PaymentService $paymentService)
    {
        $this->paymentService = $paymentService;
    }

    /**
     * Handle the event.
     *
     * @param  AccountPayment  $event
     * @return void
     */
    public function handle(AccountPayment $event)
    {
        $this->paymentService->recordPayment($event);
    }

}

However, I keep getting this error:

 - it should record payment transaction
      no beCalled([array:0]) matcher found for null.

Cannot see what I'm doing wrong here, help please.


Solution

  • function it_should_record_payment_transaction(AccountPayment $event)
    {
        $this->paymentService->recordPayment($event)->shouldBeCalled();
    }
    

    should be

    function it_should_record_payment_transaction(
        PaymentService $paymentService, 
        AccountPayment $event
    ) {
        $paymentService->recordPayment($event)->shouldBeCalled();
        $this->handle($event);
    }
    

    or

    function it_should_record_payment_transaction(AccountPayment $event) 
    {
        $prophet = new Prophet();
        $paymentService = $prophet->prophesize(PaymentService::class);
    
        $paymentService->recordPayment($event)->shouldBeCalled();
        $this->handle($event);
    
        $prophet->checkPredictions();
    }
    

    This is because, when you spec a class, you should only call a public method of it and make expectations on collaborators.

    You don't need to (and you are not supposed to do) call collaborators with

    $this->collaboratorName->method->shouldBeCalled()
    

    Use "implicit" mocks (by passing them into spec method signature: if they are used in let function and have same name and type, they are the same mock for phpspec) or "explicit" mocks that you can obtain by calling prophesize on Prophet object. The only difference between them is that "implicit" mocks are checked automatically whereas "explicit" ones need to be checked manually ($prophet->checkPredictions();)