Skip to content

RFC: New unexpected method call behaviour #528

@ciaranmcnulty

Description

@ciaranmcnulty

There will likely be errors in this, corrections/comments are welcome

inspired by this comment #527 (comment)

Motivation

#441 changed the behaviour in a way that seemed sensible at the time, but has caused DX issues. To fix I seems to require a major version bump, so let's take the chance to properly think through the behaviour and work out what's best for the next major.

Historical context

Prophecy is an opinionated tool, and we have tried to be guided not by what makes testing easy, but by what pushes developers in the right direction.

Back in the dawn of time, in the PHP 5.3 days we did not have return types. It was decided that Prophecy would essentially have two modes:

  1. for objects that haven't got any expectations, all method calls return null
  2. for objects with expectations, unexpected method calls throw an immediate exception

Spy problems

This caused issues when using a spy and also stubbing a method, cases like this would typically throw:

$stub->foo()->willReturn('bar');

$this->bar($stub);

$stub->baz()->shouldHaveBeenCalled();

This is why #441 was implemented, but this now means that the call stack for an unexpected message is messed up, and null returns then being passed on to other methods cause an error down the line before the unexpected call error would have been displayed.

Return type problems

Modern PHP is at the stage where return types can and should be added to nearly all methods. This makes the fallback behaviour far less useful as in most cases it's a type error.

New Behaviour

In a new major version, Prophecy doubles will become strict by default.

That is: even if no expectations are set they will throw an Exception at call time for any unexpected method calls with one exception: void-returning methods.

This will allow the Spy behaviour for command-like methods, as long as the baz example returns void:

$stub->foo()->willReturn('bar');

$this->bar($stub);

$stub->baz()->shouldHaveBeenCalled();

This will disallow some previous Dummy-like use of doubles

BC Impacts

Tests that don't specify return values for doubles will break unless those doubles only have void method calls.

PhpSpec and the PHPUnit-bridge depend on prophecy 1, so can choose when to expose this breaking change to their users.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions