Dimitrios Desyllas
Dimitrios Desyllas

Reputation: 10086

Mock the call of a function that exists in no class (eg php standart functions) in order to have fixed behavior

I have the following class:

namespace Utils\Random;

class RandomHelper
{   

   const LUCKY_NUMBER=3;

   public static function lucky()
   {
      return rand(0,6)==self::LUCKY_NUMBER;
   }    
}

And I want to test this class using a unit test:


namespace Tests\Random;

use PHPUnit\Framework\TestCase;

class RandomHelperTest extends TestCase
{

   public function testLucky()
   {
     // Mock rand here
     //  Here I want the rand return a value that is not 3

   }

   public function testLuckyFails()
   {
      // Mock rand here
     //  Here I want the rand return a value that is not 3
   }
}

But in order my test to be a Unit test I want to mock the php standart function rand in order to be able to have a constant result in my test.

As you can see I have conflicting needs, therefore the solution seems not to be ok with me. On one test I want to check when ther method lucky teturns true and on the other hand I want to be able when the function lucky will return false.

So do you have any idea hot to do that?

Upvotes: 1

Views: 560

Answers (1)

Dimitrios Desyllas
Dimitrios Desyllas

Reputation: 10086

The most painless way to do that is via php-mock/php-mock-phpunit package.

In your case the correct usage is:

namespace Tests\Random;

use PHPUnit\Framework\TestCase;
use Utils\Random\RandomHelper;

class RandomHelperTest extends TestCase
{

   use \phpmock\phpunit\PHPMock;

   public function testLucky()
   {
      $rand=$this->getFunctionMock('Utils\Random', "rand");
      $rand->expects($this->once())->willReturn(RandomHelper::LUCKY_NUMBER);

      $boolean=RandomHelper::lucky();

      $this->assertTrue($boolean);
   }

   public function testLuckyFails()
   {

      $rand=$this->getFunctionMock('Utils\Random', "rand");
      $rand->expects($this->once())->willReturn(0);

      $boolean=RandomHelper::lucky();

      $this->assertFalse($boolean);
   }
}

As you can see you can utilize as @Anton Mitsev says the php-mock and on the class's namespace you stub the method you want the fixed and controlled behaviour.

So a simple rule of thumb is:

  1. In not included run composer require --dev php-mock/php-mock-phpunit
  2. On each test, include the \phpmock\phpunit\PHPMock trait
  3. Find your class' namespace.
  4. Mock the function using the following approach:
 $functionMock=$this->getFunctionMock(^class_namespace^,^function_name^);
 $functionMock->expects(^expected_call_times^)->willReturn(^values^);

Upvotes: 1

Related Questions