1

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?

Dimitrios Desyllas
  • 9,082
  • 15
  • 74
  • 164
  • 1
    If it's specifically for `rand` then you can just run [srand(number)](https://www.php.net/manual/en/function.srand.php) in your test startup. If you use the same number then you'll always get the same "random" number generated. In general you should try to avoid mocking standard functions. In your particular case you can also change `RandomHelper` to not have static members and mock that instead – apokryfos Jul 02 '19 at 08:40
  • 1
    Here I found a package for this purposes: https://github.com/php-mock/php-mock – Anton Mitsev Jul 02 '19 at 08:41
  • I updated the question in order to explain better my needs. – Dimitrios Desyllas Jul 02 '19 at 08:44
  • can't you use `$v = 3; // you can change it to lucky number ` `$a = rand(0,6);` `while ($a != $v) { a$ = rand(0,6); }` `// in this line $a is a random value that is not 3 ` `// do what ever you want with it` – Alaa Morad Jul 02 '19 at 09:14
  • The implementation is dummy in order to be able to explain my problem. I could just call `Helper::lucky()` in a loop till its true. – Dimitrios Desyllas Jul 02 '19 at 09:22

1 Answers1

1

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^);
Dimitrios Desyllas
  • 9,082
  • 15
  • 74
  • 164