PHP

Guia Completo de Testes de Integração e Feature Tests com Laravel

8 min de leitura

Guia Completo de Testes de Integração e Feature Tests com Laravel

Entendendo Testes de Integração em Laravel Testes de integração verificam como múltiplos componentes da sua aplicação funcionam juntos. Diferentemente dos testes unitários, que isolam funções individuais, os testes de integração testam fluxos reais: requisições HTTP, interações com banco de dados, chamadas a serviços externos simulados. No Laravel, você trabalha com a classe que oferece helpers poderosos para simular requisições e fazer assertions sobre respostas. A grande vantagem é que você testa o sistema como um usuário real o usaria. Se sua aplicação falha quando um controller chama um repository que chama um model, o teste de integração detectará. O Laravel carrega todo o container de serviços, executa middlewares, e permite que você valide status codes, conteúdo de resposta, estado do banco de dados e headers — tudo em um único teste coesivo. Feature Tests: A Perspectiva do Usuário Feature tests (testes de funcionalidade) são um tipo específico de teste de integração que simulam comportamentos completos do usuário. Você não testa

<h2>Entendendo Testes de Integração em Laravel</h2>

<p>Testes de integração verificam como múltiplos componentes da sua aplicação funcionam juntos. Diferentemente dos testes unitários, que isolam funções individuais, os testes de integração testam fluxos reais: requisições HTTP, interações com banco de dados, chamadas a serviços externos simulados. No Laravel, você trabalha com a classe <code>TestCase</code> que oferece helpers poderosos para simular requisições e fazer assertions sobre respostas.</p>

<p>A grande vantagem é que você testa o sistema como um usuário real o usaria. Se sua aplicação falha quando um controller chama um repository que chama um model, o teste de integração detectará. O Laravel carrega todo o container de serviços, executa middlewares, e permite que você valide status codes, conteúdo de resposta, estado do banco de dados e headers — tudo em um único teste coesivo.</p>

<pre><code class="language-php">&lt;?php

namespace Tests\Feature;

use Tests\TestCase;

use App\Models\User;

class UserRegistrationTest extends TestCase

{

public function test_user_can_register()

{

$response = $this-&gt;post(&#039;/api/users&#039;, [

&#039;name&#039; =&gt; &#039;João Silva&#039;,

&#039;email&#039; =&gt; &#039;joao@example.com&#039;,

&#039;password&#039; =&gt; &#039;senhaSegura123&#039;,

&#039;password_confirmation&#039; =&gt; &#039;senhaSegura123&#039;,

]);

$response-&gt;assertStatus(201)

-&gt;assertJsonStructure([&#039;id&#039;, &#039;name&#039;, &#039;email&#039;]);

$this-&gt;assertDatabaseHas(&#039;users&#039;, [

&#039;email&#039; =&gt; &#039;joao@example.com&#039;,

]);

}

}</code></pre>

<h2>Feature Tests: A Perspectiva do Usuário</h2>

<p>Feature tests (testes de funcionalidade) são um tipo específico de teste de integração que simulam comportamentos completos do usuário. Você não testa um método isolado — testa um cenário inteiro. &quot;Um usuário faz login, navega para seu dashboard, cria um produto, e recebe uma confirmação.&quot; Isso é um feature test.</p>

<p>No Laravel, feature tests herdam de <code>TestCase</code> e estão localizados em <code>tests/Feature</code>. O framework oferece métodos como <code>actingAs()</code> para autenticar usuários, <code>withHeaders()</code> para headers customizados, e métodos fluentes para assertions em JSON e views. A filosofia é testar comportamento observável, não implementação interna.</p>

<pre><code class="language-php">&lt;?php

namespace Tests\Feature;

use Tests\TestCase;

use App\Models\User;

use App\Models\Product;

class ProductManagementTest extends TestCase

{

public function test_authenticated_user_can_create_product()

{

$user = User::factory()-&gt;create();

$response = $this-&gt;actingAs($user)

-&gt;post(&#039;/api/products&#039;, [

&#039;name&#039; =&gt; &#039;Notebook&#039;,

&#039;price&#039; =&gt; 3500.00,

&#039;description&#039; =&gt; &#039;Notebook de alta performance&#039;,

]);

$response-&gt;assertStatus(201);

$this-&gt;assertDatabaseHas(&#039;products&#039;, [

&#039;name&#039; =&gt; &#039;Notebook&#039;,

&#039;user_id&#039; =&gt; $user-&gt;id,

]);

}

public function test_unauthenticated_user_cannot_create_product()

{

$response = $this-&gt;post(&#039;/api/products&#039;, [

&#039;name&#039; =&gt; &#039;Notebook&#039;,

&#039;price&#039; =&gt; 3500.00,

]);

$response-&gt;assertStatus(401);

}

public function test_user_can_list_own_products()

{

$user = User::factory()-&gt;create();

Product::factory(3)-&gt;for($user)-&gt;create();

$response = $this-&gt;actingAs($user)-&gt;get(&#039;/api/products&#039;);

$response-&gt;assertStatus(200)

-&gt;assertJsonCount(3, &#039;data&#039;);

}

}</code></pre>

<h2>Estruturando Testes de Integração Efetivos</h2>

<p>A qualidade de seus testes depende de boa estrutura. Use factories para criar dados de teste rapidamente, organize testes em grupos temáticos, e evite testes acoplados (onde um teste depende do resultado de outro). Cada teste deve ser independente e rodar em qualquer ordem.</p>

<p>Leverage do banco de dados em transação: Laravel encapsula cada teste em uma transação que é revertida após execução, mantendo o banco limpo. Use <code>RefreshDatabase</code> no seu <code>TestCase</code> base. Estruture suas assertions para verificar o comportamento mais importante primeiro, depois detalhes. E use factories bem quando quiser dados realistas, mas mock serviços externos que não fazem parte do escopo do teste.</p>

<pre><code class="language-php">&lt;?php

namespace Tests\Feature;

use Tests\TestCase;

use App\Models\User;

use App\Models\Order;

use Illuminate\Foundation\Testing\RefreshDatabase;

class OrderProcessingTest extends TestCase

{

use RefreshDatabase;

public function test_order_is_created_with_correct_status()

{

$user = User::factory()-&gt;create();

$response = $this-&gt;actingAs($user)

-&gt;postJson(&#039;/api/orders&#039;, [

&#039;items&#039; =&gt; [

[&#039;product_id&#039; =&gt; 1, &#039;quantity&#039; =&gt; 2],

],

&#039;shipping_address&#039; =&gt; &#039;123 Main St&#039;,

]);

$response-&gt;assertCreated();

$this-&gt;assertDatabaseHas(&#039;orders&#039;, [

&#039;user_id&#039; =&gt; $user-&gt;id,

&#039;status&#039; =&gt; &#039;pending&#039;,

]);

}

public function test_order_with_invalid_product_fails()

{

$user = User::factory()-&gt;create();

$response = $this-&gt;actingAs($user)

-&gt;postJson(&#039;/api/orders&#039;, [

&#039;items&#039; =&gt; [

[&#039;product_id&#039; =&gt; 99999, &#039;quantity&#039; =&gt; 1],

],

]);

$response-&gt;assertStatus(422)

-&gt;assertJsonValidationErrors(&#039;items&#039;);

}

}</code></pre>

<h2>Melhores Práticas e Debugging</h2>

<p>Mantenha testes legíveis e bem nomeados: <code>test_authenticated_user_can_delete_own_post_but_not_others_post()</code> deixa claro o que você está testando. Use <code>dump()</code> e <code>dd()</code> durante desenvolvimento para inspecionar respostas JSON. Para testes mais complexos, considere usar Pest ou estruturas BDD (Behavior-Driven Development) que tornam a leitura ainda mais natural.</p>

<p>Moque apenas o que é externo: banco de dados real deve ser testado, mas APIs externas devem ser mockadas com <code>Http::fake()</code>. Teste casos de sucesso, casos de erro, validações, autorização, e cenários edge. Mantenha testes rápidos — se um teste leva mais de alguns segundos, revise o que você está testando. Por fim, rode seus testes frequentemente. Integre com CI/CD para rodá-los automaticamente em cada commit.</p>

<pre><code class="language-php">&lt;?php

namespace Tests\Feature;

use Tests\TestCase;

use App\Models\User;

use Illuminate\Support\Facades\Http;

class ExternalAPITest extends TestCase

{

public function test_weather_forecast_is_fetched_correctly()

{

Http::fake([

&#039;api.weather.com/*&#039; =&gt; Http::response([

&#039;temperature&#039; =&gt; 25,

&#039;condition&#039; =&gt; &#039;sunny&#039;,

]),

]);

$user = User::factory()-&gt;create();

$response = $this-&gt;actingAs($user)

-&gt;getJson(&#039;/api/weather?city=sao-paulo&#039;);

$response-&gt;assertOk()

-&gt;assertJson([

&#039;temperature&#039; =&gt; 25,

&#039;condition&#039; =&gt; &#039;sunny&#039;,

]);

}

}</code></pre>

<h2>Conclusão</h2>

<p>Testes de integração e feature tests são pilares de uma aplicação Laravel confiável. Eles validam que seus componentes trabalham em conjunto, capturando bugs que testes unitários perdem. Use <code>RefreshDatabase</code>, organize com factories, e estruture testes independentes. A prática constante com essas ferramentas transforma você em um desenvolvedor que escreve código com confiança — você saberá que suas mudanças funcionam antes de fazer deploy.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://laravel.com/docs/11/testing" target="_blank" rel="noopener noreferrer">Laravel Testing Documentation</a></li>

<li><a href="https://laravel.com/docs/11/eloquent-factories" target="_blank" rel="noopener noreferrer">Laravel Factories</a></li>

<li><a href="https://laravel.com/docs/11/http-tests" target="_blank" rel="noopener noreferrer">HTTP Testing - Laravel Docs</a></li>

<li><a href="https://pestphp.com" target="_blank" rel="noopener noreferrer">Pest PHP - Testing Framework</a></li>

<li><a href="https://www.phptesting.com/" target="_blank" rel="noopener noreferrer">Test Driven Development in PHP</a></li>

</ul>

Comentários

Mais em PHP

Boas Práticas de PSR Standards: PSR-1, PSR-2, PSR-4 e PSR-12 na Prática para Times Ágeis
Boas Práticas de PSR Standards: PSR-1, PSR-2, PSR-4 e PSR-12 na Prática para Times Ágeis

O que são PSR Standards e por que importam PSR (PHP Standards Recommendations...

Como Usar Deploy de Aplicações PHP em VPS com Nginx e PHP-FPM em Produção
Como Usar Deploy de Aplicações PHP em VPS com Nginx e PHP-FPM em Produção

Preparação da VPS e Instalação de Dependências Antes de deployar sua aplicaçã...

Dominando Sessões e Cookies: Autenticação Stateful em PHP em Projetos Reais
Dominando Sessões e Cookies: Autenticação Stateful em PHP em Projetos Reais

Entendendo Sessões e Cookies em PHP Sessões e cookies são os pilares da auten...