Laravel Testing with storage fake
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
# Mastering File Testing in Laravel: Solving the `storage::fake()` Cleanup Dilemma
As a senior developer working with Laravel, we frequently deal with file system interactionsâwhether it's uploading images, generating reports, or handling CSV exports. When testing features that interact with the `storage` facade, especially when using methods like `Storage::fake()`, developers often run into subtle issues regarding state management and cleanup.
The scenario you describedâwhere files are created during a test run but are not automatically deleted afterwardâis a very common point of confusion. This post will dive deep into why this happens with Laravel's fake storage, how to properly manage temporary files in your tests, and the best assertion strategies for validating file exports.
## Understanding `Storage::fake()` and State Management
The `Storage::fake('disk_name')` method is an incredibly powerful tool for testing because it mocks the underlying filesystem operations. It allows you to test code that reads from or writes to storage without actually touching the physical disk, making tests faster and more isolated.
However, it is crucial to understand what `Storage::fake()` *does not* do by default: **it does not automatically clean up artifacts created within the mocked disk.** When you create a file via methods like `put()`, `putFile()`, or similar operations on a fake disk, those files remain in the mock state until the test finishes, which can lead to state leakage if subsequent tests rely on a clean environment.
This behavior is intentional; it forces you, the tester, to explicitly manage the state of the mocked storage. This principle aligns with good testing practices, where you must explicitly define the setup and teardown phases for your test environment.
## The Solution: Explicit Cleanup is Mandatory
Since Laravel's fake storage doesn't automatically garbage collect created files, you must implement explicit cleanup within your test methods to ensure a clean slate for every execution. Relying on implicit deletion is risky; making the deletion explicit provides robustness.
You suggested using `Storage::disk('reportslocal')->delete($fileExported)`. This approach is absolutely correct and is the proper way to handle cleanup when dealing with mocked storage disks. You are directly interacting with the mocked filesystem interface provided by Laravel.
Here is how you can integrate this into your test function:
```php
use Illuminate\Support\Facades\Storage;
public function testAmazonDailyPendingStatusReport()
{
// 1. Setup the fake disk
Storage::fake('reportslocal');
// 2. Create the necessary objects (assuming DailyStatus and FileWriter exist)
$dailyStatus = new DailyStatus(
new FileWriter(),
new Filesystem(),
Storage::disk('reportslocal')
);
// 3. Execute the action that creates the file
$fileExported = $dailyStatus->export();
// ... [Your assertions for content and structure go here] ...
// 4. CRITICAL STEP: Explicit Cleanup
// Ensure the created file is deleted after the test runs.
Storage::disk('reportslocal')->delete($fileExported);
// continue with other assertions...
}
```
By adding the explicit `delete()` call, you guarantee that the state of the mocked storage disk is reset, preventing any accidental data leakage between tests. This disciplined approach to setup and teardown is a cornerstone of reliable testing in Laravel applications.
## Best Practices for File Content Assertions
Your initial thought process regarding assertionsâchecking existence, column numbers, headers, and valuesâis sound. When testing file exports, the quality of your assertion depends entirely on how you read the mocked file back into memory.
Instead of just checking if the file *exists* (which `Storage::fake()` helps with), you should assert the *content integrity*.
### Recommended Assertion Strategy: Read and Validate
1. **Read the Mocked File:** Use the appropriate storage method to retrieve the content that was written during the test.
2. **Parse the Content:** Since the file is a CSV, read its contents as an array or string and parse it into the structure you expect (e.g., using PHP's built-in functions or a dedicated CSV parser).
3. **Assert Structure and Data:** Compare the parsed data against your expected results from the database query.
For example, if you are testing a CSV export:
```php
// Inside your test function, after $dailyStatus->export()
$contents = Storage::disk('reportslocal')->get($fileExported);
// Assertions based on content
$expectedData = [ /* ... data retrieved from your DB setup ... */ ];
// Check if the file content matches expectations (this requires careful parsing)
expect($contents)->toBeString(); // Ensure we got string data back
// You would then implement logic to parse $contents and assert against $expectedData
```
This method ensures that you are testing the *result* of the export process, not just the existence of an artifact. As a reminder, understanding how Laravel handles file operations is key to building robust systems; exploring documentation like the official [Laravel documentation](https://laravelcompany.com) will always provide context for these facade methods.
## Conclusion
The issue you faced stems from the nature of mocking: fake storage requires explicit lifecycle management. Never assume that mocked states automatically clean up. By treating your test setup and teardown as mandatory stepsâexplicitly creating resources, executing assertions, and explicitly deleting resources using methods like `Storage::disk('reportslocal')->delete($fileExported)`âyou ensure your tests are deterministic, reliable, and maintain the high standards expected of a senior developer.