How to do simple testing of a Laravel controller?

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

How to Do Simple Testing of a Laravel Controller: Moving Beyond Manual Calls

In the world of web application development, testing is non-negotiable. Whether you are building a microservice or a large enterprise application, ensuring that your controller logic executes correctly, handles input properly, and returns the expected output is crucial.

As many developers in the community have observed, the initial desire to "just test a method" by manually instantiating classes and calling methods—like in pure PHP examples—is very intuitive. However, when working within the Laravel ecosystem, attempting this direct approach often leads to complex dependency resolution issues, as you’ve seen with FatalErrorExceptions or routing errors.

This post will guide you away from those complicated manual attempts and show you the robust, idiomatic ways to test your Laravel controllers using the tools Laravel provides.

The Laravel Philosophy: Unit vs. Feature Testing

The core shift in testing frameworks like Laravel is moving from isolated, procedural testing (calling a function directly) to Feature Testing and Unit Testing.

  1. Unit Testing: Focuses on small, isolated pieces of code, such as service classes or model logic, ensuring they work perfectly in isolation.
  2. Feature/Integration Testing: Focuses on the application as a whole—how different parts interact. For controllers, this means testing the entire request-response cycle: hitting a URL, passing data, and checking the resulting HTTP response.

Trying to manually call $controller->method() bypasses Laravel's entire infrastructure (routing, middleware, request handling), which is exactly what makes it hard to test reliably. Instead of trying to simulate an internal method call, we should simulate how a real user interacts with the application.

Method 1: Testing Controller Output via HTTP Requests

The most practical way to test a controller is by treating it as an entry point—an API or web endpoint. This approach ensures that everything, from routing to database interaction within the controller, flows correctly. We use Laravel's built-in testing features to simulate an actual browser request.

Setting up the Test Scenario

To test your ItemsController@getItemStatus method, you don't call the method directly; you simulate a user making a GET request to the corresponding route. This forces Laravel to execute all the necessary steps: resolving the route, running middleware, executing the controller logic, and generating a response.

Here is how you structure this within a PHPUnit test file:

<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class ItemsControllerTest extends TestCase
{
    use RefreshDatabase; // Ensures a clean database state for each test

    public function test_can_get_item_status_via_route()
    {
        // 1. Setup: Ensure necessary data exists in the database (e.g., an Item record)
        // $item = \App\Models\Item::factory()->create(); // Example setup

        // 2. Action: Simulate an HTTP GET request to the defined route
        $response = $this->getJson('/items/get-item-status', ['itemid' => 1]);

        // 3. Assertion: Check the resulting HTTP status code and content
        $response->assertStatus(200);
        $response->assertJson(['status' => 'active']); // Assuming the controller returns JSON data
    }
}

As you can see, this method leverages Laravel's powerful request and response system. It tests the behavior of your application rather than just the internal execution of a single function, which is far more meaningful for integration testing. This aligns perfectly with best practices when building applications on laravelcompany.com.

Method 2: Testing Controller Logic Directly (Mocking Dependencies)

If you need to test specific complex logic inside the controller without hitting the full HTTP stack (e.g., testing a private helper method or complex conditional branching), you can use mocking. This involves mocking the dependencies—like the Eloquent model—that your controller interacts with, ensuring that the controller's decision-making process is tested cleanly, regardless of the actual database state.

This technique helps you isolate the controller logic from external factors, making your tests faster and more reliable. By using mocks, you test what the controller does with the data, assuming the data provider (the model) is working correctly.

Conclusion

Stop trying to replicate procedural PHP testing inside a framework designed for request-response cycles. For Laravel controllers, the simplest and most effective way to perform "simple testing" is by embracing feature testing. By simulating HTTP requests using ->get(), you ensure that your routing, middleware, and controller execution work in harmony.

Always rely on these integrated tools rather than attempting manual method calls. This approach ensures your tests are meaningful, reliable, and scalable, which is the hallmark of professional Laravel development.