Search code examples
phplaravelunit-testingmockingmockery

Laravel Mockery: mock with return logic


I want to mock (or stub?) a class method that will return a dice result. I want the mock to return an expected value, lets say 2. But I also want my mock to return a 6 sometimes; like for example after 3:rd dice role.

To clarify, this is an example. The user has decides to role 4 dices, and I want the mock to always return 2 for every role - except for the 3:rd one which should return a 6.

Code

I am using PHP Laravel and I hope to make use of the Mockery library. This is how far I have come. My code is somewhat simplified for this example. I still have not figured out how to make a mock give different returning value depending on method arguments. Any idea how to do that?

class DiceHelper{
    protected $diceClass;
    __construct($diceClass) // I set property diceClass in constructor...

   public function roleDices($nr_of_throws){
      for($x=0; $x < count($nr_of_throws); $x++) {
         $result = $diceClass->roleOneDice($x);
       }
   }
}

class diceClass
{
   public function roleOneDice($dice_order){
      return rand(1, 6);
   }
}

Testfile

class diceLogicTest extends TestCase
{
    /** @test */
    public function role_a_dice(){
        $mock = \Mockery::mock('diceClass[roleOneDice]');
        $mock->shouldReceive("roleOneDice")->andReturn(2);

        $theHelper = new DiceHelper($mock);
        $result = $theHelper->roleDices(2);

        $this->assertEquals(4,$result ); // Returns the expected 4.
    }
}

Improvements It would be nice if there was a way that the mock could count how many times it has been called, before returning a value. That way my DiceHelper method RoleDices dont have to send the argument $x (the current dice throw order). I guess the method should not be built to make tests work.


Solution

  • This PHPUnit solution was perfect.

    $mock= $this->getMock('\diceClass');
    $mock->method('roleOneDice')->will( $this->onConsecutiveCalls(2,2,3));
    
    $theHelper = new DiceHelper($mock);
    $result = $theHelper->roleDices(3);
    $this->assertEquals(7, $result);
    

    With the use of onConsecutiveCalls it will return an expected value for each time the mock is called. The first it will return 2, and the third 3. If you call the mock more then 3 times you need more numbers - I think.