As stated in my comment, you should not Mock users. Laravel
has multiple tools to combat this, main reason is you have to mock unnecessary long call chains, static functions and partial mocking won't work with table naming and save operations. Laravel
has great testing documentation eg. testing with a database, which answers most of the best practices with testing in Laravel
.
There is two approaches from here, you can create factories that can create users that are never save in the database. Calling create()
on a factory will save it to the database, but calling make()
will fill out the model with data and not saving it.
class UserFactory extends Factory
{
public function definition()
{
return [
'name' => $this->faker->name(),
'email' => $this->faker->unique()->safeEmail(),
];
}
}
// id is normally set by database, set it to something.
$user = User::factory()->make(['id' => 42]);
Instead with both unit testing and more feature oriented testing. It is way easier to just default to using sqlite
both for performance and ease of use in a testing environment.
Add the following.
config/database.php
'sqlite' => [
'driver' => 'sqlite',
'url' => env('DATABASE_URL'),
'database' => ':memory:',
'prefix' => '',
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
],
phpunit.xml
<server name="DB_CONNECTION" value="sqlite"/>
In your test use this trait.
use RefreshDatabase;
Now you should able to use the following. This will provide a complete User model, with all the bell and whistles you needs. The only downside with sqlite
is due to which version you use, foreign keys and weird database specific features are not supported.
public function test_your_service()
{
$result = resolve(YourService::class)->saveUserData(User::factory()->create());
// assert
}