6.5 Creación de Datos Iniciales y de Prueba: Seeders, Factories y Faker

6.5.1 Introducción

En los temas anteriores aprendimos a crear tablas con migraciones y a manipular datos manualmente. Sin embargo, en muchos proyectos reales necesitamos:

  • Crear datos iniciales, como usuarios, roles o productos básicos.
  • Generar datos masivos de prueba para desarrollo y pruebas funcionales.

Laravel nos ofrece tres herramientas clave para ello:

  • Seeders: para insertar datos conocidos y permanentes.
  • Factories: para generar datos aleatorios.
  • Faker: para crear contenido realista de forma automática.

Este tema parte de un proyecto limpio (creado con laravel new) o descargado desde Git y posicionado en la rama 6.5-inicio.

Utilizaremos la base de datos cursoLaravel y actualizaremos el archivo .env para garantizar la conexión correcta.


6.5.2 Preparación del Entorno

6.5.2.1 Crear la tabla y el modelo Product

En este tema vamos manejar una tabla de productos. Creamos la migración y el modelo:

php artisan make:model Product -m

Editamos la migración:

Migración de la tabla products

1
2
3
4
5
6
7
8
Schema::create('products', function (Blueprint $table) {
    $table->id();
    $table->string('name', 50);
    $table->string('short_description', 200);
    $table->string('description', 500);
    $table->float('price')->default(20);
    $table->timestamps();
});

Editamos el modelo Product.php para permitir asignación masiva:

Modelo Product con guarded vacío

1
2
3
4
class Product extends Model
{
    protected $guarded = [];
}

Ejecutamos la migración:

php artisan migrate

6.5.2.2 Controlador, ruta y vista

Creamos el controlador:

php artisan make:controller ProductController

Ruta en web.php:

Route::get('/products', [ProductController::class, 'index'])->name('product.index');

Método index() en el controlador:

Método index

1
2
3
4
5
public function index()
{
    $products = Product::all();
    return view('product.index', compact('products'));
}

Antes de crear la vista vamos a crear el layout layouts/app.blade.php para que todas las vistas tengan un diseño común.

Layout app.blade.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@yield('title', 'Mi Aplicación')</title>
</head>
<body>
    <header>
        <h1>Mi Tienda</h1>
        <!-- Aquí podría ir una barra de navegación -->
    </header>

    <main>
        @yield('content')
    </main>

    <footer>
        <p>&copy; {{ date('Y') }} Mi Tienda</p>
    </footer>
</body>
</html>

Creamos resources/views/product/index.blade.php:

En este caso la vista es sencilla, solo muestra una lista de productos, en forma de cards. Más adelante con CSS ya le cambiaremos el aspecto. Utilizamos @forelse para mostrar un mensaje si no hay productos.

Vista index.blade.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@extends ('layouts.app')

@section('title', 'Products')

@section('content')
    <div class="product-container">
        @forelse ($products as $product)
            <div class="card">
                <h2>{{ $product->name }}</h2>
                <p>{{ $product->short_description }}</p>
                <p><strong>${{ $product->price }}</strong></p>
            </div>
        @empty
            <p>No hay productos disponibles.</p>
        @endforelse
    </div>
@endsection

Añadimos un par de reglas CSS en public/css/app.css para mejorar la presentación de la vista:

.product-container {
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
}

.card {
    border: 1px solid #ccc;
    padding: 15px;
    width: 200px;
    box-shadow: 2px 2px 10px rgba(0,0,0,0.1);
}

Nos falta añadir el CSS a la vista. Editamos el layout app.blade.php para incluir el CSS:

Layout app.blade.php con CSS

1
2
3
4
5
<head>
    ...
    <link rel="stylesheet" href="{{ asset('css/app.css') }}">
    ...
</head>

6.5.3 Seeders

6.5.3.1 Introducción a Seeders

Los seeders permiten poblar la base de datos con datos iniciales que queremos tener siempre disponibles.

6.5.3.2 Crear y registrar un seeder

php artisan make:seeder ProductSeeder

En el seeder:

ProductSeeder con 4 productos

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php

namespace Database\Seeders;

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\Product;

class ProductSeeder extends Seeder
{
    /**
    * Run the database seeds.
    */
    public function run(): void
    {
        // Vamos a crear 4 productos de ejemplo
        Product::create([
            'name' => 'Producto 1',
            'short_description' => 'Descripción del producto 1',
            'description' => 'Descripción larga del producto 1',
            'price' => 20.00,
        ]);
        Product::create([
            'name' => 'Producto 2',
            'short_description' => 'Descripción del producto 2',
            'description' => 'Descripción larga del producto 2',
            'price' => 30.00,
        ]);
        Product::create([
            'name' => 'Producto 3',
            'short_description' => 'Descripción del producto 3',
            'description' => 'Descripción larga del producto 3',
            'price' => 40.00,
        ]);
        Product::create([
            'name' => 'Producto 4',
            'short_description' => 'Descripción del producto 4',
            'description' => 'Descripción larga del producto 4',
            'price' => 50.00,
        ]);
    }
}

Editamos DatabaseSeeder.php para incluirlo:

1
2
3
4
5
 public function run(): void
    {
       $this->call(ProductSeeder::class);

    }

Ejecutamos:

php artisan db:seed

6.5.3.3 Ejecutar un seeder específico

php artisan db:seed --class=ProductSeeder

6.5.4 Factories

6.5.4.1 Introducción a Factories

Las factories permiten generar muchos datos automáticamente para pruebas y desarrollo.

6.5.4.2 Crear una factory

php artisan make:factory ProductFactory --model=Product

Definición simple:

Factory inicial (manual)

1
2
3
4
5
6
7
8
9
public function definition(): array
{
    return [
        'name' => Str::random(10),
        'short_description' => Str::random(30),
        'description' => Str::random(50),
        'price' => random_int(5, 100),
    ];
}

Modificamos el modelo Product.php para usar la factory:

Modelo Product con factory

1
2
3
4
5
6
class Product extends Model
{
    use HasFactory;

    protected $guarded = [];
}

6.5.4.3 Usar factory en un seeder

Modificamos el contenido del seeder ProductSeeder.php para usar la factory. En la función run() quitamos los prodcutos que habíamos creado manualmente y añadimos la factory:

Product::factory()->count(10)->create();

6.5.5 Faker

6.5.5.1 Introducción a Faker

Faker genera datos aleatorios que parecen reales (nombres, direcciones, textos...). Laravel lo usa integrado en Factory.

6.5.5.2 Tabla de métodos útiles de Faker

Método Descripción Ejemplo
name() Nombre completo Juan Pérez
email() Email realista juan@mail.com
sentence(n) Frase con n palabras Lorem ipsum dolor sit amet.
paragraph() Párrafo de texto Lorem ipsum dolor sit amet...
text(n) Texto de longitud n Texto aleatorio
word() Una palabra aleatoria laptop
numberBetween(a, b) Número entre a y b 47
randomElement([...]) Valor de un array 'IT'
boolean() true o false aleatorio true
date() Fecha aleatoria 2023-01-15
company() Nombre de empresa Grupo Pérez SL

6.5.5.3 Aplicar Faker a ProductFactory

ProductFactory con faker

1
2
3
4
5
6
7
8
9
public function definition(): array
{
    return [
        'name' => $this->faker->word(),
        'short_description' => $this->faker->sentence(5),
        'description' => $this->faker->paragraph(),
        'price' => $this->faker->numberBetween(10, 100)
    ];
}

Ejecutamos migraciones y seeders de nuevo:

php artisan migrate:fresh --seed

Comprobamos la vista: productos aleatorios, pero ahora realistas.


6.5.6 Conclusiones

  • Los seeders son útiles para poblar la base de datos con datos estáticos.
  • Las factories permiten generar cientos de registros en segundos.
  • Faker mejora la calidad de los datos de prueba.
  • Todo esto acelera y mejora el desarrollo realista de tu aplicación.

Proximo tema: relaciones entre tablas (hasMany, belongsTo, etc.).


6.5.7 Ejercicio Práctico

Crea una tabla de empleados y genera 100 empleados con datos aleatorios usando una factory y Faker.

Ver solución propuesta
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Migración de empleados
Schema::create('employees', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->string('department');
    $table->decimal('salary', 8, 2);
    $table->timestamps();
});

// EmployeeFactory.php
public function definition(): array
{
    return [
        'name' => $this->faker->name(),
        'email' => $this->faker->unique()->safeEmail(),
        'department' => $this->faker->randomElement(['IT', 'HR', 'Marketing']),
        'salary' => $this->faker->numberBetween(20000, 60000),
    ];
}

// EmployeeSeeder.php
public function run(): void
{
    Employee::factory()->count(100)->create();
}

// DatabaseSeeder.php
public function run(): void
{
    $this->call(EmployeeSeeder::class);
}