Os testes unitários desempenham um papel crucial no desenvolvimento de software, garantindo que cada parte do código funcione conforme o esperado. Em projetos Laravel, onde a utilização de filas é comum para processamento em segundo plano, é essencial garantir que essas filas sejam testadas de forma adequada.
Vamos implementar testes na fila de sincronização de dados do projeto product-api.
Product API
Rode o composer install:
composer install
Após a instalação, o script ./init.sh
será chamado para:
- Instalar o MySQL
- Criar o banco usado pela API.
- Criar no banco o usuário utilizado pela API.
- Rodar as migrações.
- Gerar o swaager.json
- Rodar os testes.
- Startar a aplicação.
About Laravel
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
- Simple, fast routing engine.
- Powerful dependency injection container.
- Multiple back-ends for session and cache storage.
- Expressive, intuitive database ORM.
- Database agnostic schema migrations.
- Robust background job processing.
- Real-time event broadcasting.
Laravel is accessible, powerful, and provides tools required for large, robust applications.
Learning Laravel
Laravel has the most extensive and thorough documentation and video…
Antes de começar, confira meu artigo onde explico como implementar o Laravel Queue em seu projeto, seguindo padrões para manter seu código testável.
No meu caso, optei por criar os testes após a implementação da fila. Contudo, vale destacar que a abordagem inversa, onde os testes são criados antes da implementação, também é válida e pode ser adotada conforme a preferência em seu projeto.
Crie um novo teste com o comando artisan make:test. Para fins de organização, criarei meus testes dentro da pasta Plataform1, pois meu job faz sinc de produtos com esse módulo.
php artisan make:test Plataform1/ProductSyncTest
O primeiro método que vamos criar, será responsável por testar o despache do nosso job para a fila. Não estranhe o tamanho do nome do método, pois prefiro que seja descritivo e claro em relação à sua funcionalidade.
Vamos usar umaQueue fake para testar os despaches e vamos despachar os jobs.
Queue::fake();
$productSync = new ProductSync();
$queue = 'data_sync';
ProductSyncJob::dispatch($productSync)->onQueue($queue);
Agora, verificaremos se ProductSyncJob foi despachado para data_sync.
Queue::assertPushedOn($queue, ProductSyncJob::class);
Vamos despachar mais dois jobs e fazer uma nova afirmação.
Queue::bulk([
new ProductSyncJob($productSync),
new ProductSyncJob($productSync),
], '', $queue);
Queue::assertPushed(ProductSyncJob::class, 3);
Caso você implemente o despache de jobs com o facade Bus, também poderá testa-lo.
Bus::fake();
Bus::batch([
new ProductSyncJob($productSync),
new ProductSyncJob($productSync),
])->onQueue($queue)->dispatch();
Bus::assertBatched(function (PendingBatchFake $batch) {
return count($batch->jobs) === 2;
});
A implementação do nosso primeiro teste ficará assim.
<?php
namespace Tests\Feature\Plataform1;
use App\Jobs\Plataform1\ProductSyncJob;
use App\Services\Plataform1\ProductSync;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Testing\Fakes\PendingBatchFake;
use Tests\TestCase;
class ProductSyncTest extends TestCase
{
public function test_dispatching_the_product_sync_job_to_the_queue(): void
{
Queue::fake();
$productSync = new ProductSync();
$queue = 'data_sync';
ProductSyncJob::dispatch($productSync)->onQueue($queue);
Queue::assertPushedOn($queue, ProductSyncJob::class);
Queue::bulk([
new ProductSyncJob($productSync),
new ProductSyncJob($productSync),
], '', $queue);
Queue::assertPushed(ProductSyncJob::class, 3);
Bus::fake();
Bus::batch([
new ProductSyncJob($productSync),
new ProductSyncJob($productSync),
])->onQueue($queue)->dispatch();
Bus::assertBatched(function (PendingBatchFake $batch) {
return count($batch->jobs) === 2;
});
}
}
Você pode ajustar o teste de acordo com a necessidade do seu projeto, Laravel é um framework altamente testável e rico em recursos de teste.
Agora, vamos criar um teste chamado test_product_sync para o serviço ProductSync que injetamos em ProductSyncJob. Conhecer a implementação de ProductSync é fundamental para o entendimento do próximo teste. Você pode verificar sua implementação no artigo ou repositório mencionado anteriormente.
Vamos pegar a url que recebe as requisições e criar dois arrays de produtos.
$plataform1Url = config('integration.plataform1')['api']['url'];
$data1 = Plataform1Product::factory()
->count(10)
->make()
->toArray();
$data2 = Plataform1Product::factory()
->count(10)
->make()
->toArray();
Agora, criaremos uma closure que retornará nosso response baseado nos parâmetros.
$json = fn ($page, $nextPage) => [
'next_page' => $nextPage,
'data' => match ($page) {
1 => $data1,
2 => $data2,
}
];
Então, vamos mockar os requests recebidos no endpoint, instanciar ProductSync e chamar o método execute.
Http::fake([
$plataform1Url.'/v1/products?page=1' => Http::response($json(1, 2)),
$plataform1Url.'/v1/products?page=2' => Http::response($json(2, null)),
]);
$productSync = new ProductSync();
$productSync->execute();
Faremos três afirmações, que nossa tabela de produto tem um produto de $data1, um produto de $data2 e que após truncar, o produto estará ausente.
$this->assertDatabaseHas('product', ['id' => $data1[0]['id']]);
$this->assertDatabaseHas('product', ['id' => $data2[0]['id']]);
Product::truncate();
$this->assertDatabaseMissing('product', ['id' => $data1[0]['id']]);
A implementação do nosso segundo teste ficará assim.
public function test_product_sync(): void
{
$plataform1Url = config('integration.plataform1')['api']['url'];
$data1 = Plataform1Product::factory()
->count(10)
->make()
->toArray();
$data2 = Plataform1Product::factory()
->count(10)
->make()
->toArray();
$json = fn ($page, $nextPage) => [
'next_page' => $nextPage,
'data' => match ($page) {
1 => $data1,
2 => $data2,
}
];
Http::fake([
$plataform1Url.'/v1/products?page=1' => Http::response($json(1, 2)),
$plataform1Url.'/v1/products?page=2' => Http::response($json(2, null)),
]);
$productSync = new ProductSync();
$productSync->execute();
$this->assertDatabaseHas('product', ['id' => $data1[0]['id']]);
$this->assertDatabaseHas('product', ['id' => $data2[0]['id']]);
Product::truncate();
$this->assertDatabaseMissing('product', ['id' => $data1[0]['id']]);
}
Antes de executarmos os testes, realizaremos algumas configurações para que o teste utilize um banco SQLite em memória.
Em phpunit.xml adicione as seguintes variáveis.
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
Dentro de nossa classe de teste, use a trait RefreshDatabase.
use RefreshDatabase;
Finalmente, vamos rodar nossos testes.
php artisan test
// opcionalmente, você pode passar o caminho do arquivo que deseja testar
php artisan test path/to/file
Neste artigo, exploramos a importância dos testes em filas de projetos Laravel, destacando como eles fortalecem a confiabilidade das aplicações. Ao adotar práticas de teste eficazes, garantimos que a execução assíncrona e a gestão de filas sejam mais consistentes. A integração de testes sólidos contribui para a construção de sistemas mais resilientes em ambientes de produção.
Top comments (0)