Factories e Seeders com Laravel



This content originally appeared on DEV Community and was authored by Paula Araujo

Seeders e Factories são ferramentas poderosas no Laravel que ajudam a popular o banco de dados com dados de teste ou iniciais.

Esse será o primeiro artigo de uma série visando ajudar a comunidade Laravel a aprender melhores conceitos sobre a ferramenta.

Pré-requisitos: Laravel 12, PHP 8.3, Composer instalado e familiaridade básica com Eloquent.

Tabela de Conteúdo

  1. Prólogo
  2. O que são Seeders e Factories?
  3. Por que usar Seeders e Factories?
  4. Criando e Utilizando Factories
    • Criando uma Factory
    • Criando ‘states’ dentro de uma Factory
  5. Criando e Utilizando Seeders
    • Criando um Seeder
    • Executando Seeders
  6. Relacionamentos com Factories
  7. Conclusão
  8. Referências

1. Prólogo

Até não muito tempo atrás, na hora de popular um banco de dados, eu tinha o costume de utilizar funções do próprio Eloquent, escrevendo na mão os User::create([...]) da vida e passando os dados que queria. Quando chega em certo ponto do crescimento do projeto, isso se torna repetitivo e difícil de manter, fora a dificuldade de simular cenários.

Isso aconteceu até eu descobrir os queridos chamados Seeders e Factoriesdo Laravel, que foram os responsáveis por tornar essa tarefa muito mais agradável e fácil de manter e executar.

Se assim como a eu do passado você luta para mockar dados, podemos mudar isso!

Neste artigo, você vai aprender:

  • O que são Seeders e Factories
  • Como criar e configurar
  • Boas práticas para cenários reais
  • Uso avançado com relacionamentos

2. O que são Seeders e Factories?

As Factories são as responsáveis por gerar os dados falsos de maneira automatizada, enquanto os Seeders serão os responsáveis por “ativar” essas Factories e inserir os dados desejados no banco.

Então, os objetos prontos criados pelas Factories são perfeitos para cenários de testes.

Por exemplo: em uma UserFactory nós definimos para que ela gere usuários que possuem nome, e-mail, documento e senha de forma completamente aleatória. E pode ser criado em massa!

Model vs Factory : um espelho. Models precisam dos “fillables” para preencher os campos no banco de dados, enquanto Factories usam esses campos para gerar dados falsos.

Com essa definição, na chamada do Seeder ele irá “ativar” as Factories desejadas e popular o banco de dados.

Factory: classe que define atributos falsos (fake data) por meio da biblioteca Faker. Seeder: classe que orquestra a execução de Factories e insere dados no banco.

3. Por que usar Seeders e Factories?

Se a explicação sobre o que são ainda não o convenceu, posso citar alguns motivos para utilizá-los:

  • A criação de dados para teste é muito mais rápida;
  • A simulação é realista, podendo representar cenários complexos, pois considera o relacionamento entre os modelos e pode gerar dados em grande volume;
  • São fáceis de manter, reproduzir e adicionar informações.
  • Diminuem muito o risco de erros na inserção de dados manuais.
  • Aumentam a confiabilidade na hora de partir para cenários mais complexos.

Com tudo isso, podemos gerar cenários consistentes em nosso projeto e tornar nosso ambiente mais previsível em relação à modelagem feita. Na hora de fazer os testes, essas coisas são muito valiosas!

4. Criando e utilizando Factories

Pra gente começar, vamos lembrar que o Laravel tem uma ferramenta maravilhosa para criação de qualquer coisa: o Artisan.

4.1 Criando uma Factory

Primeiro vamos criar uma nova Factory no nosso projeto. Com o artisan você consegue fazer isso de um jeito bem simples:

php artisan make:factory --help
# Description:
#  Create a new model factory

# Usage:
#  make:factory [options] [--] <name>

# Arguments:
#  name                  The name of the factory

# Options:
#  -m, --model[=MODEL]   The name of the model


php artisan make:factory UserFactory --model=User

Esse comando irá gerar uma classe database/factories/UserFactory.php, tendo como base a model User, com a seguinte estrutura considerando uma model User padrão:

use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;

class UserFactory extends Factory
{
    protected $model = User::class;

    public function definition()
    {
        return [
            'name' => $this->faker->name(),
            'email' => $this->faker->unique()->safeEmail(),
            'email_verified_at' => now(),
            'role' => $this->faker->randomElement(['admin', 'user']), 
            'password' => bcrypt('password'),
        ];
    }
}

O método definition() é onde serão definidos os atributos e os valores que deverão ser gerados. Já no valor do atributo, podemos ver o Faker, que é uma biblioteca do Laravel e vai ser o seu maior aliado na hora de gerar dados falsos de forma rápida.

Dentro dele existem métodos para escolher o tipo de dado que precisa gerar, no exemplo acima ele gera um nome e um e-mail seguro aleatórios. Mas ele pode gerar outros tipos de dados também, como datas, textos, um número dentro de um intervalo desejado e até mesmo CPF!

Esse último eu descobri recentemente. Para ter acesso a ele e outras coisas como RG e CNPJ, basta mudar o valor do APP_FAKER_LOCALE no seu .env para pt_BR e prontinho!

APP_FAKER_LOCALE="pt_BR" 

Certifique-se de atualizar o .env.example com o novo APP_FAKER_LOCALE para não dar erro em uma nova instalação.

Agora você pode gerar documentos brasileiros aleatórios também.

4.2 Criando ‘states’ dentro de uma factory

Os “States” são métodos de manipulação que podem ser inseridos na “Factory” caso a “Model” tenha diferentes estados para algum atributo, como, por exemplo, um usuário que pode ser “admin” ou usuário comum, com e-mail verificado ou não.

Para a construção desses estados, a estrutura será a seguinte:

class UserFactory extends Factory  
    {

    public function isAdmin(): static  
    {  
        return $this->state(fn (array $attributes) => [  
            'role' => 'admin',  
        ]);  
    }

    public function regularUser(): static  
    {  
        return $this->state(fn (array $attributes) => [  
            'role' => 'user',   
        ]);  
    }

    public function unverified(): static  
    {  
        return $this->state(fn (array $attributes) => [  
            'email_verified_at' => null,  
        ]);  
    }
}

Criados os states, podemos utilizá-los da seguinte maneira:

User::factory()
    ->isAdmin()
    ->create();

User::factory()
    ->regularUser()
    ->unverified()
    ->create();

Neste bloco de código, criamos dois usuários. O primeiro será definido como “admin” e o segundo, como usuário comum. No segundo, utilizei o estado que define o e-mail como não verificado.

A utilização de estados é muito útil para a realização de testes controlados, pois permite simular cenários específicos e traduzir regras de negócio. Por exemplo, podemos gerar um usuário “admin” para conferir se as permissões e os acessos estão corretos para esse nível.

5. Criando e Utilizando Seeders

Agora que sabemos criar Factories, vamos para os Seeders. Assim como nas Factories, podemos contar com o apoio do Artisan.

5.1 Criando um Seeder

Comando básico no terminal:

php artisan make:seeder --help
#Description:
#  Create a new seeder class

#Usage:
#  make:seeder <name>

#Arguments:
#  name                  The name of the seeder

php artisan make:seeder UserSeeder

Esse comando irá gerar uma classe database/seeders/UserSeeder.php com a seguinte estrutura:

namespace Database\Seeders;  

use Illuminate\Database\Console\Seeds\WithoutModelEvents;  
use Illuminate\Database\Seeder;  

class UserSeeder extends Seeder  
{    
     public function run(): void  
    {  
        //  
    }  
}

O método run() é o que será executado e onde iremos definir o que queremos que seja inserido no banco de dados.

5.2 Executando Seeders

Para rodar um seeder específico, o comando no terminal deverá ser utilizado dessa forma:

php artisan db:seed --class=UserSeeder

Mas podemos também rodar todos os Seeders a partir do DatabaseSeeder.php que já vem por padrão em um projeto Laravel. Para isso, basta estruturar método run() do DatabaseSeeder.php da seguinte forma:

class UserSeeder extends Seeder  
{  
    public function run()
    {
        $this->call([
            UserSeeder::class
        ]);
    }
}

É possível também optar por não criar Seeders separados e construir direto no DatabaseSeeder.php quais dados deseja inserir utilizando as Factories. Ficando dessa forma:

class UserSeeder extends Seeder  
{  
    public function run()
    {
        User::factory()
            ->isAdmin()
            ->create();

        User::factory()
            ->regularUser()
            ->unverified()
            ->create();
    }
}

Após decidir qual abordagem faz mais sentido para o seu projeto, sem especificar um Seeder, execute o seguinte comando no terminal:

php artisan db:seed

Sem uma especificação de Seeder no comando, o DatabaseSeeder é o que será executado, com o que foi colocado dentro do método run().

Para ajudar com testes, é legal também utilizar um Seeder específico para visualizar um ambiente controlado e que mostre todas as informações básicas do projeto, como um EssentialSeeder.

Utilizando de exemplo um projeto em que estou trabalhando atualmente (que será incluído nas referências desse artigo), para me ajudar a visualizar as informações dele em sua totalidade posso criar um EssentialSeeder que crie um usuário que pertence a um empresa e que essa empresa possua um número de vouchers ativos e vouchers utilizados.

Quando for executado apenas este Seeder, poderei ter uma previsão de como serão as telas em um caso real.

6. Relacionamentos com Factories

Em aplicações reais as Models têm relações entre si. Um usuário que possui um perfil, um pedido de compra que possui muitos items por exemplo.

Para criar um usuário que possua um perfil com seus detalhes ligados a ele, iremos utilizar o método has():

User::factory()  
    ->has(Profile::factory())
    ->unverified()  
    ->create();

Note que também podemos combinar com states criados anteriormente.

Agora, se já temos um user criado previamente e queremos vincular um perfil a ele, utilizamos o for() ao invés do has(). Desta forma:

$user = User::factory()->create();

Profile::factory()
    ->for($user) // Associa ao usuário criado acima
    ->create();

7. Conclusão

Com Seeders e Factories é possível popular seu banco de dados de forma consistente, gerar modelos em poucos segundos evitando repetição de código e conseguindo nesse processo uma forma fácil e rápida de testar qualquer cenário específico que deseja. Tudo isso com um código fácil de dar manutenção posteriormente!

Um ponto importante também é que é a primeira vez que escrevo um artigo técnico na vida. Fiz tudo isso aqui pra te convencer que vale muito a pena começar a utilizar Seeders e Factories no seu projeto. 😉

Quero deixar também um agradecimento aos revisores do artigo:

Atualmente trabalho em uma empresa de consultoria financeira que tem serviços personalizados voltados a desenvolvedores! Você consegue saber mais aqui:
Fire|ce – Code Capital


This content originally appeared on DEV Community and was authored by Paula Araujo