php-mock/php-mock-phpunit
Integrate php-mock with PHPUnit to mock built-in PHP functions (like time(), file_get_contents(), etc.) in a controlled, namespaced way. Ideal for unit tests that need to simulate IO, time, and other global behaviors without changing production code.
Install: Run composer require --dev php-mock/php-mock-phpunit
Enable the trait: In your test class, use the PHPMock\PHPUnit\MockFunction trait
Start mocking: Call mockFunction() inside your test to intercept built-in functions like time(), rand(), file_exists(), etc.
use PHPMock\PHPUnit\MockFunction;
class MyTest extends TestCase {
use MockFunction;
public function testTimeIsMocked(): void {
$this->mockFunction('time', 1234567890);
$this->assertEquals(1234567890, time());
}
}
Scope matters: By default, mocks apply only within the current test method and are automatically cleaned up after each test.
Time-dependent tests: Mock time() or date_default_timezone_set() to avoid flaky tests that depend on real clock time.
$this->mockFunction('time', strtotime('2020-01-01 00:00:00'));
$this->assertEquals('2020', date('Y'));
Randomness control: Replace rand(), mt_rand(), or random_int() with deterministic values.
$this->mockFunction('rand', 42);
$this->assertEquals(42, rand());
File I/O isolation: Mock file_exists(), file_get_contents(), file_put_contents() to simulate filesystem conditions.
$this->mockFunction('file_exists', false);
$this->assertFalse(file_exists('/nonexistent'));
Namespacing: When mocking within a namespaced class (e.g., App\Services\MyService), use the namespace option:
$this->mockFunction('App\Services\time', 1234567890);
// Now App\Services\time() returns 1234567890, not global time()
Stacking mocks: You can call mockFunction() multiple times per test — each call overrides the previous for the same function in the current scope.
Global vs. namespaced functions: mockFunction('time') only mocks the global time(). If your class uses time() inside namespace App\Services, you must mock App\Services\time. Use use function App\Services\time; in the class to avoid confusion.
No redeclaration allowed: You cannot mock functions in classes using function_exists() checks — PHP doesn’t allow re-declaring functions, but this package uses runtime function replacement, so it works — but only if the function hasn’t been called before mocking.
Avoid mocking in bootstrap/autoload: Don’t mock functions in global scope or auto-loaded files — mocks may not apply consistently if the function was already resolved.
Testing class methods calling global functions: Ensure the class under test calls the unqualified function (e.g., time() instead of \time()), otherwise the mock won’t intercept it.
CI pitfalls: Ensure no Xdebug or OPcache optimizations interfere — set opcache.enable=0 in CI php.ini if tests behave oddly.
Custom functions: This package only mocks internal PHP functions — you cannot mock user-defined functions. It is not a substitute for dependency injection for your own logic.
Extensibility: If you need global mocks across tests, extend the PHPMock\TestCase base class instead of using the trait (though trait is preferred for clarity and safety).
Performance: Mocking adds slight overhead — disable it in large test suites if not needed; prefer DI for production code where possible.
How can I help you explore Laravel packages today?