Trucos para probar aplicaciones web Laravel usando fábricas de modelos

Introducción


Imaginemos que estamos desarrollando una pequeña aplicación web en la versión Laravel superior a 6 y queremos escribir pruebas para ella.


El contenido del artículo se detalla a continuación:


  1. Descripción del dominio
  2. Creación de aplicaciones
  3. Creación de entidad
  4. Pruebas de escritura
  5. Problema
  6. Decisión

Descripción del dominio


Desarrollaremos una tienda en línea en la que ciertos usuarios pueden hacer un pedido determinado. De lo anterior se deduce que las principales entidades del área temática serán el usuario, el pedido y los bienes. Existe una relación de uno a muchos entre el usuario y el pedido, es decir, el usuario puede tener muchos pedidos y el pedido solo tiene un usuario (se requiere un usuario para el pedido). Existe una relación de muchos a muchos entre el pedido y los bienes, porque los bienes pueden estar en diferentes pedidos y el pedido puede consistir en muchos bienes. Por simplicidad, omitimos productos y nos enfocamos solo en usuarios y pedidos.


Creación de aplicaciones


Las aplicaciones Laravel son muy fáciles de construir utilizando el paquete de creador de aplicaciones . Después de instalarlo, la creación de una nueva aplicación se ajusta a un comando:


laravel new shop

Creación de entidad


, — . Laravel , . , . :


php artisan make:model Order -m -f

App/, database/migrations/ database/factories/.


. , . - :


<?php

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

class CreateOrdersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('orders', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('user_id');
            $table->timestamps();

            $table->foreign('user_id')->references('id')->on('users')
                ->onDelete('cascade');
        });
    }

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

. fillable :


<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Order extends Model
{
    protected $fillable = ['user_id'];

    /**
     * Relation to user
     * @return BelongsTo
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
}

. , , id.


<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Order;
use App\User;
use Faker\Generator as Faker;

$factory->define(Order::class, function (Faker $faker) {
    return [
        'user_id' => factory(User::class)->create()->id
    ];
});

, .



, Laravel PHPUnit . :


php artisan make:test OrderTest

tests/Feature/. RefreshDatabase.


№1.


<?php

namespace Tests\Feature;

use App\Order;
use App\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class OrderTest extends TestCase
{
    use RefreshDatabase;

    /** @test */
    public function order_factory_can_create_order()
    {
        // When we use Order factory
        $order = factory(Order::class)->create();
        // Then we should have new Order::class instance
        $this->assertInstanceOf(Order::class, $order);
    }
}

!


№2.


/** @test */
public function order_should_have_user_relation()
{
    // When we use Order factory
    $order = factory(Order::class)->create();
    // Then we should have new Order::class instance with user relation
    $this->assertNotEmpty($order->user_id);
    $this->assertInstanceOf(User::class, $order->user);
}

!


№3. ,


/** @test */
public function we_can_provide_user_id_to_order_factory()
{
    // Given user
    $user = factory(User::class)->create();
    // When we use Order factory and provide user_id parameter
    $order = factory(Order::class)->create(['user_id' => $user->id]);
    // Then we should have new Order::class instance with provided user_id
    $this->assertEquals($user->id, $order->user_id);
}

!


, , . , , .


№4. ,


/** @test */
public function when_we_create_one_order_one_user_should_be_created()
{
    // Given user
    $user = factory(User::class)->create();
    // When we use Order factory and provide user_id parameter
    $order = factory(Order::class)->create(['user_id' => $user->id]);
    // Then we should have new Order::class instance with provided user_id
    $this->assertEquals($user->id, $order->user_id);
    // Let's check that system has one user in DB
    $this->assertEquals(1, User::count());
}

! , . ? .



, , — . , , . . , , . , .



, . PHP , n- — func_get_arg(), . , () Faker, — , create() . , , () . , , . :


$factory->define(Order::class, function (Faker $faker) {
    //    
    $passedArguments = func_get_arg(1);
    return [
        'user_id' => function () use ($passedArguments) {
            //    user_id,   
            if (! array_key_exists('user_id', $passedArguments)) {
                return factory(User::class)->create()->id;
            }
        }
    ];
});

№4 — !


Eso es todo lo que quería compartir. A menudo me encuentro con el problema de que es necesario controlar el número de entidades después de alguna acción dentro del sistema, y ​​la implementación estándar de fábrica realmente no hace frente a esto.


Estaré encantado de escuchar tus trucos que utilizas cuando desarrollas en Laravel o PHP.


All Articles