Как мокнуть несколько php функций внутри одного класса phpunit тестов?
Мне надо мокнуть нативные функции wordpress: current_user_can и get_current_user_id. Мокаю я их в разных тестах с помощью PHP-Mock. В первом тесте работает (смотри примеры ниже) а втором уже нет. Но если во втором сменить функцию тоже на get_current_user_id то тогда мок работает и во втором тесте.
Тестируемый метод (namespace Hacc\Inc\Models;):
/**
* Set balance.
*
* @param float $balance
*
* @throws AccessDeniedException
*/
public function setBalance(float $balance): void
{
if (current_user_can('manage_options')
|| get_current_user_id() === $this->ownerId
|| (
$this->getOwner()->getFamily()->isMember(get_current_user_id())
&& true === $this->familyVisibility
)
) {
$this->balance = $balance;
} else {
throw new AccessDeniedException();
}
}
Тесты:
<?php
namespace Hacc\Tests\Inc\Models;
use Hacc\Inc\Exceptions\AccessDeniedException;
use Hacc\Inc\Exceptions\HaccException;
use Hacc\Inc\Exceptions\NewInstanceException;
use Hacc\Inc\Models\Wallet;
use phpmock\environment\MockEnvironment;
use phpmock\functions\FixedValueFunction;
use phpmock\Mock;
use phpmock\MockBuilder;
use phpmock\MockEnabledException;
use PHPUnit\Framework\TestCase;
/**
* Class WalletTest
*
* @author Rodkin Yevhenii <[email protected]>
* @package Hacc\Tests\Inc\Models
*
* @coversDefaultClass \Hacc\Inc\Models\Wallet
*/
class WalletTest extends TestCase
{
/**
* @var int
*/
public $wallet_id;
/**
* @throws HaccException
*/
public function setUp(): void
{
$this->wallet_id = Wallet::create('Test common wallet', 2);
}
/**
* @throws AccessDeniedException
* @throws HaccException
* @throws MockEnabledException
* @throws NewInstanceException
*/
public function tearDown(): void
{
$mock = $this->mockFunction('get_current_user_id', 2);
try {
$mock->enable();
$wallet = Wallet::getInstance($this->wallet_id);
$wallet->deleteWallet();
} finally {
$mock->disable();
}
}
/**
* Test wallet balance setter.
*
* @throws MockEnabledException
* @throws AccessDeniedException
* @throws NewInstanceException
*
* @covers ::setBalance
* @covers ::getBalance
*/
public function testSetBalance(): void
{
$mock = $this->mockFunction('get_current_user_id', 2);
$wallet = Wallet::getInstance($this->wallet_id);
try {
$mock->enable();
$wallet->setBalance(20.75);
$this->assertEquals(20.75, $wallet->getBalance());
} finally {
$mock->disable();
}
}
/**
* Test wallet balance setter by admin.
*
* @throws MockEnabledException
* @throws AccessDeniedException
* @throws NewInstanceException
*
* @covers ::setBalance
* @covers ::getBalance
*/
public function testSetBalanceByAdmin(): void
{
$mock = $this->mockFunction('current_user_can', true);
$wallet = Wallet::getInstance($this->wallet_id);
try {
$mock->enable();
$wallet->setBalance(7.25);
} finally {
$mock->disable();
}
$this->assertEquals(7.25, $wallet->getBalance());
}
/**
* Create mock function.
*
* @param string $function Function name.
* @param mixed $returnVal The value witch will be return.
* @param string $namespace Namespace.
*
* @return Mock
*/
protected function mockFunction(string $function, $returnVal, string $namespace = 'Hacc\Inc\Models'): Mock
{
$builder = new MockBuilder();
$builder->setNamespace($namespace)
->setName($function)
->setFunctionProvider(
new FixedValueFunction($returnVal)
);
return $builder->build();
}
}
Ответы (1 шт):
Автор решения: Евгений Родкин
→ Ссылка
Решил эту проблему без использования мокеров. Я в начала файла тестов объявил namescpace тестируемого класса и в нём переопределил нужные мне функции. Получилось так:
<?php
namespace Hacc\Inc\Models;
/**
* Mock of current_user_can function.
*
* @param string $capability
*
* @return mixed
*/
function current_user_can(string $capability)
{
global $current_user_can;
return $current_user_can ?? \current_user_can($capability);
}
/**
* Mock of get_current_user_id function.
*/
function get_current_user_id()
{
global $get_current_user_id;
return $get_current_user_id ?? \get_current_user_id();
}
namespace Hacc\Tests\Inc\Models;
/**
* Reset global variables.
*/
function resetGlobals()
{
global $current_user_can;
global $get_current_user_id;
unset($_GLOBAL['current_user_can']);
unset($_GLOBAL['get_current_user_id']);
}
use Hacc\Inc\Exceptions\AccessDeniedException;
use Hacc\Inc\Exceptions\HaccException;
use Hacc\Inc\Exceptions\NewInstanceException;
use Hacc\Inc\Models\Member;
use Hacc\Inc\Models\Wallet;
use PHPUnit\Framework\TestCase;
/**
* Class WalletTest
*
* @author Rodkin Yevhenii <[email protected]>
* @package Hacc\Tests\Inc\Models
*
* @coversDefaultClass \Hacc\Inc\Models\Wallet
*/
class WalletTest extends TestCase
{
/**
* @var int
*/
public $wallet_id;
/**
* Test wallet balance setter.
*
* @param Wallet $wallet Wallet instance.
*
* @throws AccessDeniedException
* @throws HaccException
*
* @depends testGetInstance
* @covers ::setBalance
* @covers ::getBalance
*/
public function testSetBalance(Wallet $wallet): void
{
global $get_current_user_id;
$get_current_user_id = 2;
try {
$wallet->setBalance(20.75);
$this->assertEquals(20.75, $wallet->getBalance());
} finally {
resetGlobals();
}
}
/**
* Test wallet balance setter by admin.
*
* @param Wallet $wallet Wallet instance.
*
* @throws AccessDeniedException
* @throws HaccException
*
* @depends testGetInstance
* @covers ::setBalance
* @covers ::getBalance
*/
public function testSetBalanceByAdmin(Wallet $wallet): void
{
global $current_user_can;
$current_user_can = true;
try {
$wallet->setBalance(7.25);
$this->assertEquals(7.25, $wallet->getBalance());
} finally {
resetGlobals();
}
}
}