Unit test OverflowException: Maximum retries reached 10,000 times, unique value still not found
P粉186897465
P粉186897465 2024-04-06 11:27:39
0
2
505

So I'm doing some unit testing before implementing new features. I run the test but it fails with OverflowException: Maximum retries reached 10000 but unique value not found This is the test I am running.

public function test_job_factory()
    {
        $client = Client::factory()->create();
        $accountHandler = AccountHandler::factory()->create();
        $user = User::factory()->create();

        $this->post('/login', [
            'email' => $user->email,
            'password' => 'password',
        ]);

        $user->givePermissionTo( 'manage jobs' );
        $clientContact = ClientContact::factory()->create();
        $job = Job::factory()->create();

        $this->assertTrue($job->id > 0);
    }

The error seems to occur when creating the job itself. The test above tested other plants and is working.

This is the JobFactory.php file:

<?php

namespace Database\Factories;

use App\Models\AccountHandler;
use App\Models\Client;
use App\Models\ClientContact;
use App\Models\Job;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Job>
 */
class JobFactory extends Factory
{
    protected $model = Job::class;

    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition()
    {
        return [
            'title'              => $this->faker->company(),
            'is_active'          => 1,
            'is_draft'           => 0,
            'client_id'          => $this->faker->unique()->numberBetween(1, Client::count()),
            'account_handler_id' => $this->faker->unique()->numberBetween(1, AccountHandler::count()),
            'eclipse_contact_id' => $this->faker->unique()->numberBetween(1, User::count()),
            'client_contact_id'  => $this->faker->unique()->numberBetween(1, ClientContact::count()),
            'description'        => $this->faker->paragraphs(1),
        ];
    }
}

And the migration for this (create_jobs_table.php):

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('jobs', function (Blueprint $table) {
            $table->id('number');
            $table->boolean( 'is_active' )->default(true);
            $table->boolean( 'is_complete' )->default(true);
            $table->string('title', 64)->nullable();
            $table->timestamps();
            $table->foreignId('author')->nullable()->constrained()->references('id')->on('users');
            $table->text('description')->nullable();
            $table->foreignId('client_id')->nullable()->constrained()->references('id')->on('clients');
            $table->foreignId('client_contact_id')->nullable()->constrained()->references('id')->on('client_contacts');
            $table->foreignId('account_handler_id')->nullable()->constrained()->references('id')->on('account_handlers');
            $table->date('expiry_date')->nullable();
            $table->date('artwork_deadline')->nullable();
            $table->date('proof_deadline')->nullable();
            $table->integer('redirect')->nullable();
            $table->boolean( 'is_draft' )->default(true);
            $table->foreignId('eclipse_contact_id')->nullable()->constrained()->references('id')->on('users');
            $table->foreignId('subscription_id')->nullable()->constrained()->references('id')->on('subscriptions');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('jobs');
    }
};

So what went wrong and why does this loop occur? I've added the minimum data required to create the job, so not sure what I'm missing.

Thanks

*** edit *** I was asked to provide a link to where I found the bad practice of using unique and numberBetween, here is an example This won't work like you're looking for!

P粉186897465
P粉186897465

reply all(2)
P粉442576165

The problem is when you try to get 5 values ​​between 1 and 5 (Inclusive), you can only take 4. The 5th number will never exceed unique() Verification.

This is because, for example, when you run the first instance of unique

$faker->unique()->numberBetween(1, 20)

Then run it in another factory, laravel usually extends the previous instance (I guess), if that makes sense. But when you pass true like below

$faker->unique(true)->numberBetween(1, 20)

It starts searching again from 1 to 20

This solved my problem.

Therefore always pass true in unique()

instances
P粉164942791

I recommend following the documented approach to solving this problem. https://laravel.com/docs/9.x/database-test#factoryrelationship

Looking at your migration table, there's a good chance your factory won't work because you're indicating the relationship at the SQL level, which basically forces you to have the records in the related table, otherwise SQL will throw an error..

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template