avris/function-mock
Mock PHP functions in unit tests without changing your code. avris/function-mock lets you replace and control built-in and user-defined function calls at runtime, making it easier to test legacy code, edge cases, and hard-to-isolate behavior.
file_get_contents, date, or custom globals like config()). It aligns with Laravel’s testing philosophy by enabling deterministic, isolated tests without refactoring legacy code.app()->make() directly). The package’s namespace-scoped mocks prevent test pollution in large codebases.str_replace in a StringHelper class.file_get_contents to avoid real HTTP calls.Feature tests where real interactions are needed.setUp()/tearDown().beforeEach/afterEach.Testing traits.createApplication() for bootstrapped tests.php artisan test --env=testing).| Risk | Laravel-Specific Impact | Mitigation |
|---|---|---|
| Namespace Collisions | Custom str_replace in app vs. PHP’s str_replace. |
Use fully qualified names (e.g., \str_replace) or whitelist functions. |
| Laravel Helpers | Mocking app(), config(), or route() fails. |
Extend the package or use Laravel’s MockApplication instead. |
| Test Pollution | Unmocked functions break subsequent tests. | Enforce FunctionMock::unmockAll() in tearDown(). |
| Performance in CI | Slow test suites if overused. | Benchmark and limit to high-impact functions (e.g., file_get_contents). |
app()->make())? If so, this package is insufficient—consider Mockery or Laravel\Testing\TestCase.helper('str')) that need mocking? This package won’t work; a wrapper would be needed.partialMock) or supplement it?DB::select())? Use Laravel’s DatabaseMigrations instead.file_get_contents while migrating to Guzzle)?MockApplication: Better for container mocking.runkit (if available).setUp()/tearDown().beforeEach/afterEach for mock lifecycle.BootstrapTesting.DB::*: Use Laravel’s DatabaseTransactions or RefreshDatabase instead.grep -r "file_get_contents\|date\|config(" app/ to identify global function calls.file_get_contents) in a FeatureTest.Mockery/PHPUnit mocks for globals.tests/TestCase.php).dd()").| Laravel Component | Compatibility Notes |
|---|---|
| Service Container | No direct integration; mocks must be initialized manually. |
| Artisan Commands | Works in CLI tests (e.g., php artisan test). |
| Queues/Jobs | Mock global functions in Handle classes (e.g., dispatch(new Job())). |
| Middleware | Avoid mocking request()/response()—use Laravel’s HttpTestCase instead. |
| Events/Listeners | Mock global functions in event handlers (e.g., EventServiceProvider). |
composer require avris/function-mock --dev
Add to tests/TestCase.php:
use Avris\FunctionMock\FunctionMock;
protected function tearDown(): void
{
FunctionMock::unmockAll();
parent::tearDown();
}
public function test_file_get_contents_mock()
{
FunctionMock::mock('file_get_contents', fn() => 'fake-content');
$result = file_get_contents('https://example.com');
$this->assertEquals('fake-content', $result);
}
beforeEach(function () {
FunctionMock::mock('date', fn() => '2023-01-01');
});
FunctionMock::mock('log_error', function ($message) {
$this->fail("Unexpected error: {$message}");
});
$mock = FunctionMock::mock('json_encode');
json_encode(['test' => true]);
$mock->assertCalled();
namespace App\Testing;
use Avris\FunctionMock\FunctionMock;
class LaravelFunctionMock extends FunctionMock
{
public static function mockInContainer(string $function, callable $callback)
{
// Add Laravel-specific logic (e.g., container binding)
}
}
TESTING_GLOBALS.md file listing safe-to-mock functions.str_replace vs. \str_replace).$this->assertFalse(FunctionMock::isMocked('file_get_contents'));
FunctionMock::getMockedFunctions() to list active mocks.globalFunction rule).file_get_contents in unit tests).--parallel (no shared state).How can I help you explore Laravel packages today?