Introdução
Vamos imaginar que estamos desenvolvendo uma pequena aplicação Web na versão Laravel superior a 6 e queremos escrever testes para ela.
O conteúdo do artigo é fornecido abaixo:
- Descrição de Domínio
- Criação de aplicativo
- Criação de Entidades
- Testes de escrita
- Problema
- Decisão
Descrição de Domínio
Vamos desenvolver uma loja online na qual determinados usuários podem fazer um determinado pedido. Pelo exposto, concluímos que as principais entidades da área de assunto serão o usuário, o pedido e as mercadorias. Há uma comunicação de um para muitos entre o usuário e o pedido, ou seja, o usuário pode ter muitos pedidos e o pedido possui apenas um usuário (para o pedido, é necessária a presença do usuário). Há um relacionamento muitos-para-muitos entre o pedido e os bens, porque os bens podem estar em pedidos diferentes e o pedido pode consistir em muitos bens. Por simplicidade, omitimos produtos e focamos apenas em usuários e pedidos.
Criação de aplicativo
Os aplicativos Laravel são muito fáceis de construir usando o pacote do criador de aplicativos . Após a instalação, a criação de um novo aplicativo se encaixa em um comando:
laravel new shop
Criação de Entidades
, — . 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
{
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');
});
}
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'];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
. , , id.
<?php
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;
public function order_factory_can_create_order()
{
$order = factory(Order::class)->create();
$this->assertInstanceOf(Order::class, $order);
}
}
!
№2.
public function order_should_have_user_relation()
{
$order = factory(Order::class)->create();
$this->assertNotEmpty($order->user_id);
$this->assertInstanceOf(User::class, $order->user);
}
!
№3. ,
public function we_can_provide_user_id_to_order_factory()
{
$user = factory(User::class)->create();
$order = factory(Order::class)->create(['user_id' => $user->id]);
$this->assertEquals($user->id, $order->user_id);
}
!
, , . , , .
№4. ,
public function when_we_create_one_order_one_user_should_be_created()
{
$user = factory(User::class)->create();
$order = factory(Order::class)->create(['user_id' => $user->id]);
$this->assertEquals($user->id, $order->user_id);
$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) {
if (! array_key_exists('user_id', $passedArguments)) {
return factory(User::class)->create()->id;
}
}
];
});
№4 — !
Isso é tudo que eu queria compartilhar. Costumo encontrar o problema de que é necessário controlar o número de entidades após alguma ação dentro do sistema, e a implementação padrão da fábrica realmente não lida com isso.
Ficarei feliz em ouvir seus truques que você usa ao desenvolver no Laravel ou PHP.