phpspec / prophecy

Highly opinionated mocking framework for PHP 5.3+
MIT License
8.53k stars 241 forks source link

Add ChainPromise and willChain method to MethodProphecy #510

Closed bfolliot closed 3 years ago

bfolliot commented 3 years ago

I needed to chain several different promises, in the same way that we can return several values with willReturn.

First example : a method should not be called more than once

$myProphecy->execute()
    ->willChain(
        new ReturnPromise(['a returned value']),
        new ThrowPromise(new Exception('Failure'))
    );

Second example : the SUT must retry three times in case of failure of $myProphecy (fault tolerance)

$myProphecy->execute()
    ->willChain(
        new ThrowPromise(new Exception('First failure')),
        new ThrowPromise(new Exception('Second failure')),
        new ThrowPromise(new Exception('Third failure')),
        new ReturnPromise(['a returned value'])
    );
bfolliot commented 3 years ago

In ChainPromiseSpec, I couldn't use :

$firstPromise->execute([], $object, $method)->shouldHaveBeenCalled();

because Prophecy refuses to pass ObjectProphecy to a prophecy, I don't know why.

I was able to do it in MethodProphecySpec.

ciaranmcnulty commented 3 years ago

You can achieve this behaviour by chaining will():

$myProphecy->execute()
    ->will(
        function() use ($myProphecy) {
            $myProphecy->execute()->willThrow(new Exception('Failure'));

            return ['a returned value'];
        }
    );

I'm in two minds whether adding to the API (and encouraging the use of raw Promises like that) is the best approach

Is there a more fluent syntax we could adopt?

ciaranmcnulty commented 3 years ago

I'm reluctantly closing - I don't really like the Chain syntax but am open to other suggestions for the same use case that are more prophecy-esque