TDD in Laravel using phpunit for REST Api Development
Tags: tdd, phpunit, api, laravel
Published: 2020-07-07 13:43:00

---
title: TDD in Laravel using phpunit for REST Api Development
published: true
description: Get started with TDD in Laravel using phpunit for REST Api Development. As an example, I will be creating an api using TDD approach to allow user to update his profile.
tags: tdd, phpunit, api, laravel
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/l9zgc77fxtinpvaotcr6.png
---
Get started with TDD in Laravel using phpunit for REST Api Development. As an example, I will be creating an api using TDD approach to allow user to update his profile.

You can also watch the entire example here:
{% youtube G-OV9Eqsouk %}

The idea behind TDD approach is to first make the test case before writing the actual code. So writing api code becomes easy once you have already figured out all the thing you will be doing in api while writing the test case.
Once you have a test case in place then after each change in API you can validate if your api is working as expected by running the test case.

If you look into **phpunit.xml**. You will see environment variables defined like this.
```php
    <php>
        <server name="APP_ENV" value="testing"/>
        <server name="BCRYPT_ROUNDS" value="4"/>
        <server name="CACHE_DRIVER" value="array"/>
        <server name="DB_CONNECTION" value="sqlite"/>
        <server name="DB_DATABASE" value=":memory:"/>
        <server name="MAIL_MAILER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
    </php>
```

These environment variable are used while running test cases. Laravel will automatically set the environment variables defined in this file.

One thing to note here is that We are using in memory database of sqlite. The advantage of using memory database is that it is created automatically in memory when you run your tests and are automatically deleted after your test cases are completed. 

It will not affect your actual database in use.

![](https://media.giphy.com/media/l2R024uE283zkmdfW/giphy.gif)

You can configure these  environment variables as per your requirement.

Open TestCase file. We will have to make some changes here to migrate and seed database before test case. For this override **setUp** function like this.

```php
<?php

namespace Tests;

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Foundation\Testing\WithFaker;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication, WithFaker;

    protected function setUp(): void {
        parent::setUp();

        $this->artisan('migrate');
        $this->artisan('db:seed');

        $this->withoutExceptionHandling(); //To get the actual Exception whenever it occurs instead of Laravel handing the exception.

    }
}
```

Let's try to create a new test using command:
```bash
php artisan make:test UserTest
```
Open **tests/Feature/UsersTest.php**

Write your first test case like this:
```php
<?php

namespace Tests\Feature;

use App\User;
use Tests\TestCase;
use JWTAuth;

class UsersTest extends TestCase
{
    /** @test */
    public function a_user_can_edit_his_profile() {
        $user = User::first();

        $token = JWTAuth::fromUser($user);

        $attributes = ['name' => $this->faker->name];

        $this->patchJson('api/user/profile', $attributes, ['authorization' => "bearer $token"])
            ->assertStatus(200);

        $this->assertDatabaseHas($user->getTable(), array_merge($attributes, [
            'id' => $user->id
        ]));
    }
}
```

Here i'm using JWT but you can change it as per the package you are using to generate auth token.

I'm using **assertDatabaseHas** function and passing table name and the data which should be present to check if the profile is updated in database.

Now, if we try to run it will fail because we haven’t created the api route yet.
![](https://media.giphy.com/media/1yjLtcHe5XVGHlA6Kf/giphy.gif)

Let’s do that in api.php
```php
Route::patch('user/profile','UserController@updateProfile');
```

Create a new controller using command:
```bash
php artisan make:controller UserController
```

Write **updateProfile** function in **UserController** to allow user to edit his profile like this:
```php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth:api');
    }

    public function updateProfile() {
        $attributes = request()->validate(['name' => 'required|string']);

        auth()->user()->update($attributes);

        return response()->json(["msg" => "Profile successfully updated"]);
    }
}
```

Try running your test case again and your test case should pass this time.
![Test Case Passed](https://dev-to-uploads.s3.amazonaws.com/i/7duxa5tx036htx3wtuct.png)

That's it!

Hope you find this useful!