When we use test double feature, we mock services and pretend like we call them. When we don't use test double feature, we don't mock services and call them directly. In the case of test double, the example below would not make sense because if you break tested classes, your test testGetUsersWithMock() would still pass because the it is not actually calling the tested classes. I am just showing you how both options can be used.


ParameterUtil


namespace Application\Util;

class ParameterUtil
{
const MIN_PAGE = 0;
const MAX_LIMIT = 5;
const MIN_LIMIT = 1;

public function getPage($page)
{
if (!$page || $page < 1) {
$page = self::MIN_PAGE;
}

return (int) $page;
}

public function getLimit($limit)
{
if (!$limit || $limit < 1) {
$limit = self::MIN_LIMIT;
} elseif ($limit > self::MAX_LIMIT) {
$limit = self::MAX_LIMIT;
}

return (int) $limit;
}
}

UserService


namespace Application\Service;

use Application\Util\ParameterUtil;

class UserService
{
const USERS = [
'User 1',
'User 2',
'User 3',
'User 4',
'User 5',
'User 6',
'User 7',
'User 8',
'User 9',
'User 10',
];

private $parameterUtil;

public function __construct(ParameterUtil $parameterUtil)
{
$this->parameterUtil = $parameterUtil;
}

public function get($page = null, $limit = null)
{
$page = $this->parameterUtil->getPage($page);
$limit = $this->parameterUtil->getLimit($limit);

return array_slice(self::USERS, $page, $limit);
}
}

UserServiceTest


namespace tests\Application\Service;

use Application\Service\UserService;
use Application\Util\ParameterUtil;
use PHPUnit\Framework\TestCase;

class UserServiceTest extends TestCase
{
/** @var ParameterUtil */
private $parameterUtil;

protected function setUp()
{
$this->parameterUtil = new ParameterUtil();
}

protected function tearDown()
{
$this->parameterUtil = null;
}

/**
* @dataProvider getUsersDataProvider
*/
public function testGetUsers($page, $limit, $expected)
{
$userService = new UserService($this->parameterUtil);

$result = $userService->get($page, $limit);

$this->assertEquals($expected, $result);
}

/**
* @dataProvider getUsersDataProvider
*/
public function testGetUsersWithMock($page, $limit, $expected)
{
$userService = $this->getMockBuilder(UserService::class)
->setConstructorArgs([$this->parameterUtil])
->getMock();

$userService->expects($this->any())
->method('get')
->will($this->returnValue($expected));

$this->assertEquals($expected, $userService->get($page, $limit));
}

public function getUsersDataProvider()
{
return [
[null, null, ['User 1']],
[1, null, ['User 2']],
[null, 1, ['User 1']],
[1, 1, ['User 2']],
[2, 1, ['User 3']],
[2, 2, ['User 3', 'User 4']],
];
}
}

Test


$ vendor/bin/phpunit
PHPUnit 5.7.22 by Sebastian Bergmann and contributors.

............ 12 / 12 (100%)

Time: 23 ms, Memory: 3.75MB

OK (12 tests, 12 assertions)