Tricks zum Testen von Laravel-Webanwendungen mithilfe von Modellfabriken

Einführung


Stellen wir uns vor, wir entwickeln eine kleine Webanwendung für eine Laravel-Version über 6 und möchten Tests dafür schreiben.


Der Inhalt des Artikels ist unten angegeben:


  1. Domänenbeschreibung
  2. Anwendungserstellung
  3. Entitätserstellung
  4. Tests schreiben
  5. Problem
  6. Entscheidung

Domänenbeschreibung


Wir werden einen Online-Shop entwickeln, in dem bestimmte Benutzer eine bestimmte Bestellung aufgeben können. Aus dem oben Gesagten ergibt sich, dass die Hauptentitäten des Themenbereichs der Benutzer, die Bestellung und die Waren sind. Es gibt eine Eins-zu-Viele-Beziehung zwischen dem Benutzer und der Bestellung, dh der Benutzer kann viele Bestellungen haben, und die Bestellung hat nur einen Benutzer (für die Bestellung ist ein Benutzer erforderlich). Es gibt eine Viele-zu-Viele-Beziehung zwischen der Bestellung und der Ware, da die Ware in verschiedenen Bestellungen sein kann und die Bestellung aus vielen Waren bestehen kann. Der Einfachheit halber lassen wir Produkte weg und konzentrieren uns nur auf Benutzer und Bestellungen.


Anwendungserstellung


Laravel-Anwendungen lassen sich mit dem Application Maker-Paket sehr einfach erstellen . Nach der Installation passt das Erstellen einer neuen Anwendung in einen Befehl:


laravel new shop

Entitätserstellung


, — . 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 — !


Das ist alles was ich teilen wollte. Ich stoße oft auf das Problem, dass es notwendig ist, die Anzahl der Entitäten nach einer Aktion innerhalb des Systems zu steuern, und die Standard-Factory-Implementierung kommt damit nicht wirklich zurecht.


Ich werde mich freuen, Ihre Tricks zu hören, die Sie bei der Entwicklung in Laravel oder PHP verwenden.


All Articles