Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

marbobo's avatar
Level 12

How do you UNIT test your controller?

Hi. I really dont do unit testing on my controllers classes. And I just got a tasks that requires me to do it. can you guys give me some idea on how to UNIT test a controller class ?

0 likes
8 replies
jlrdw's avatar

@jeffreyway has videos on testing. Some are free. But I'd say yes test certain methods, I don't know about testing a whole controller.

2 likes
Tippin's avatar

Testing controllers to me is more feature/integration. Thus I do my http test to check validation, authorization and responses. I keep my controllers slim however, so any events or actions my controllers use are tested on their own. My "controller" test basically look more like these:

    /** @test */
    public function user_can_send_image_message()
    {
        $this->expectsEvents([
            NewMessageBroadcast::class,
            NewMessageEvent::class,
        ]);

        $this->actingAs($this->tippin);

        $this->postJson(route('api.messenger.threads.images.store', [
            'thread' => $this->private->id,
        ]), [
            'image' => UploadedFile::fake()->image('picture.jpg'),
            'temporary_id' => '123-456-789',
        ])
            ->assertSuccessful()
            ->assertJson([
                'thread_id' => $this->private->id,
                'temporary_id' => '123-456-789',
                'type' => 1,
                'type_verbose' => 'IMAGE_MESSAGE',
                'owner' => [
                    'provider_id' => $this->tippin->getKey(),
                    'provider_alias' => 'user',
                    'name' => 'Richard Tippin',
                ],
            ]);
    }

    /**
     * @test
     * @dataProvider imageValidation
     * @param $imageValue
     */
    public function send_image_message_validates_image_file($imageValue)
    {
        $this->actingAs($this->tippin);

        $this->postJson(route('api.messenger.threads.images.store', [
            'thread' => $this->private->id,
        ]), [
            'image' => $imageValue,
            'temporary_id' => '123-456-789',
        ])
            ->assertStatus(422)
            ->assertJsonValidationErrors('image');
    }

    public function imageValidation(): array
    {
        return [
            'Image cannot be empty' => [''],
            'Image cannot be integer' => [5],
            'Image cannot be null' => [null],
            'Image cannot be an array' => [[1, 2]],
            'Image cannot be a movie' => [UploadedFile::fake()->create('movie.mov', 500, 'video/quicktime')],
            'Image must be under 5mb' => [UploadedFile::fake()->create('image.jpg', 6000, 'image/jpeg')],
            'Image cannot be a pdf' => [UploadedFile::fake()->create('test.pdf', 500, 'application/pdf')],
        ];
    }
2 likes
jlrdw's avatar

@tippin great answer.

@kevdev notice the test, and all the things the image cannot be.

So unless checking all those things when actually uploading an image, you may as well not test.

Just saying I have seen test pass, but when really updating, uploading, etc there be a problem.

A test is only good if it mirrors what the method will do "real World".

1 like
marbobo's avatar
Level 12

yes. actually i got confuse also. the tasks is UNIT testing controller and what I have in mind is testing it using HTTP test

martinbean's avatar
Level 80

@kevdev You wouldn’t unit test a controller. A unit test should test one single unit of code (such as a method) without dependencies. It’s nigh-on impossible to unit test a controller because it relies on so much context: a router, middleware, requests and responses, etc.

You’ll find difficulty unit-testing a controller as Laravel’s unit test classes extends PHPUnit’s base TestCase class. Instead, you’ll need to create a feature test, which boots the framework in their setUp methods, and will give you helpers for testing HTTP requests such as $this->post, $this->assertSuccessful, etc.

If you’re writing a unit test and struggling because you need access to the framework, or resources like a database, then that’s a good indicator that what you’re writing is not a unit test.

4 likes
cleargoal's avatar

@martinbean can you explain, please, how to call some method of the controller in the test's code? I'm a newbie in testing and get difficulties collecting the right info about testing.

1 like
automica's avatar

@cleargoal You could something like the following:

$this
->get('/url/to/controller')
->assertStatus(200)
->assertJsonFragment(['foo'=>'bar']);

The above example gets a specific url path, checks you get a 200 response and then looks for a certain set of data in the output.

if you are trying to test a rendered front end, then you look at something like laravel dusk, that uses a headless chrome browser to load the path as if it was being viewed as human and then runs tests against that.

https://laravel.com/docs/10.x/dusk

start a new topic if you have any specific questions on this.

Please or to participate in this conversation.