Partial Overrides
Partial Overrides is commonly used in integration tests, when you want to run a real class but disable or replace specific side effects.
The class executes normally. Only the methods you explicitly override behave differently.
Example: integration test with a disabled side effect
group("Test payment transaction", function (TestCase $case) {
// Wrap the real service
$service = $case->wrap(App\Service\PaymentService::class);
// Replace the method that performs the external request
$service->override('sendRequest', function (array $payload) {
return [
'status' => 200,
'transaction_id' => 'tx_test_123',
'transaction_status' => 'authorised',
];
});
// Run the real integration flow
$result = $service->processPayment(100);
// Validate the result
$case->expect($result)
->hasValueAt('transaction_status', 'authorised')
->hasValueAt('transaction_id', 'tx_test_123')
->validate();
});
This test executes the real processPayment() logic, including validation rules and internal state changes.
Only the outbound request is replaced.
What wrap() does
$case->wrap() creates a real instance of the class and allows individual methods to be controlled during the test.
- All methods behave exactly as in production by default
- Only overridden methods are affected
- The instance can be used like a normal object
Wrapping does not simulate behavior. It runs real code.
Overriding methods
An override replaces the body of a single method for the duration of the test.
$service->override('sendRequest', function (array $payload) {
return ['status' => 200];
});
Inside the override, $this refers to the real class instance. You can call other original methods if needed.
Only that method is replaced. Everything else remains unchanged.
Adding test-only methods
You can add helper methods that exist only during the test.
$service->add('processWithoutRetry', function (int $amount) {
return $this->processPayment($amount);
});
These methods are useful for orchestration or inspection and are never part of production code.
Calling methods dynamically
If you need to call a method by name, use:
$service->this('processPayment', 100);
This simply calls the method on the wrapped instance and respects overrides.
When to use partial overrides
Use partial overrides when:
- You are writing integration tests
- You want real behavior, not a fake implementation
- One or two methods cause unwanted side effects
- You want to avoid refactoring production code just to satisfy a test
If you need to replace many methods or assert interactions, use the mocker instead.