In this article will showing how excute a phpunit for SQLite in laravel.

In here should prepare mysql and setting .env for database info.

First, create a hello model and use the -m options for generate a migration file

php artisan make:model Hello --m

Just need add name column in hello_table migration file:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateHellosTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('hellos', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('hellos');
    }
}

Excute artisan migrate command for generate table:

php artisan migrate

In here we make a repository for access Hello model, and HelloService will access HelloRepository, and HelloControler.

Also, generate service and repository test.

php artisan make:controller ../Repositorys/HelloRepository
php artisan make:controller ../Services/HelloServices
php artisan make:controller HelloController
php artisan make:test HelloServiceTest
php artisan make:test HelloRepositorytest

Prepare seeder for unittest:

php artisan make:seeder HelloSeeder

HelloSeeder.php

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

use App\Models\Hello;

class HelloSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $hello = new Hello;
        $hello->name = 'hello-unittest';
        $results = $hello->save();
    }
}

Add HelloSeeder to DatabaseSeeder caller:

DatabaseSeeder.php

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call([
            HelloSeeder::class,
        ]);
    }
}

SQLite for unittest

Mac has include SQLite in environment:

sqlite3

In here, we need use sqlite for unittest.

First, setting .env.testing as fellowing:

.env.testing

DB_CONNECTION=sqlite
DB_DATABASE=':memory:

Second, setting phpunit.xml, open sqlite and database information:

phpunit.xml

<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         colors="true"
>
    <testsuites>
        <testsuite name="Unit">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>
        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>
    </testsuites>
    <coverage processUncoveredFiles="true">
        <include>
            <directory suffix=".php">./app</directory>
        </include>
    </coverage>
    <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="database/database.sqlite"/>
        <server name="MAIL_MAILER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
        <server name="TELESCOPE_ENABLED" value="false"/>
    </php>
</phpunit>

Setting database config, add sqlite

config/database.php

        'sqlite' => [
            'driver' => 'sqlite',
            'url' => env('DATABASE_URL'),
            'database' => env('DB_DATABASE', database_path('database.sqlite')),
            'prefix' => '',
            'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
        ],

create database.sqlite

touch database/database.sqlite

Prepare TestCase for sqlite

tests/TestCase.php

<?php
declare(strict_types=1);

namespace Tests;

use Illuminate\Support\Facades\Artisan;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication;

    protected function initDatabase()
    {

        Artisan::call('migrate');
        Artisan::call('db:seed --class=HelloSeeder');
    }

    protected function resetDatabase()
    {
        Artisan::call('migrate:reset');
    }
}

tests/Feature/HelloRepositoryTest.php

<?php

namespace Tests\Feature;

use App\Models\Hello;

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

class HelloRepositorytestTest extends TestCase
{
    use RefreshDatabase;
    public function setUp(): void
    {
        parent::setUp();
        $this->initDatabase();
    }

    public function tearDown(): void
    {
        $this->resetDatabase();
        parent::tearDown();
    }

    /**
     * test create data
     * @return void
     */
    public function testCreateData()
    {
        $hello = new Hello;
        $hello->name = 'hihi';
        $condition = $hello->save();
        $this->asserttrue($condition);

        $expected = 'hihi';
        $actual = $hello->name;
        $this->assertsame($expected, $actual);
    }

    /**
     * test query data
     * @return void
     */
    public function testQueryData()
    {
        $hello = Hello::query()
            ->first();
        $expected = 'hello-unittest';
        $actual = $hello->name;
        $this->assertsame($expected, $actual);
    }
}

Run your test

sqlite3 database/database.sqlite


sqlite>.tables
hellos      migrations

sqlite> select * from migrations;
1|2021_06_07_234357_create_hellos_table|1

test controller

HelloController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Services\HelloServices;

class HelloController extends Controller
{
    protected $HelloServices;
    public function __construct(HelloServices $HelloServices) {
        $this->HelloServices = $HelloServices;
    }

    public function get() {
        $result = $this->HelloServices->get();

        return $result;
    }

    public function update(Request $request):bool {
       $id = $request->id;
       $name = $request->name;
       $result = $this->HelloServices->updateOne(['id'=>$id, 'name'=>$name]);
       return $result;
    }

    public function create(Request $request):bool {
        $name = $request->name;
        $result = $this->HelloServices->addOne($name);
        return $result;
    }
}

api.php


Route::get('/hellos', [HelloController::class, 'get'] );
Route::post('/hellos/update', [HelloController::class, 'update'] );
Route::post('/hellos/create', [HelloController::class, 'create'] );

HelloServices.php

<?php

namespace App\Http\Services;
use App\Http\Repositorys\HelloRepository;
use Illuminate\Database\Eloquent\Collection;

class HelloServices
{

    protected $HelloRepository;

    /**
     * @param App\Http\Repositorys\HelloRepository $HelloRepository
     */
    public function __construct(HelloRepository $HelloRepository) {
        $this->HelloRepository = $HelloRepository;
    }
    public function get():Collection {
        return $this->HelloRepository->fetchHello();
    }

    public function addOne(string $name):bool {
        return $this->HelloRepository->createHello($name);
    }

    public function updateOne(array $data):bool {
        return $this->HelloRepository->updateHello($data);
    }
}

Write create and update data for controller

HelloController.php

<?php

namespace Tests\Feature;

use Tests\TestCase;
use App\Models\Hello;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;

class HelloControllerTest extends TestCase
{
    use RefreshDatabase;

    /**
     * Test hello contoller add one
     *
     * @return void
     */
    public function testHelloControllerAddOne()
    {
        $response = $this->post('/api/hellos/create', ['name'=>'halo']);
        $response->assertStatus(200);

        $hello = Hello::query()
            ->where('name', 'halo')
            ->first();
        $expected = 'halo';
        $actual = $hello->name;
        $this->assertsame($expected, $actual);
    }

    /**
     * Test hello contoller update one
     *
     * @return void
     */
    public function testHelloControllerUpdateOne()
    {
        $hello = new Hello;
        $hello->name = 'this is test add one';
        $hello->save();
        $id = $hello->id;

        $response = $this->post('/api/hellos/update', ['id'=>$id, 'name'=>'this is test update one']);
        $response->assertStatus(200);

        $hello = Hello::query()
            ->where('id', $id)
            ->first();
        $expected = 'this is test update one';
        $actual = $hello->name;
        $this->assertsame($expected, $actual);
    }


    /**
     * Test hello contoller get data
     *
     * @return void
     */
    public function testHelloControllerFetchData()
    {

        $hello = new Hello;
        $hello->name = 'this is test add one';
        $hello->save();
        $id = $hello->id;

        $response = $this->get('/api/hellos');
        $response->assertStatus(200);
        $response->assertSeeText('this is test add one', $escaped = true);
        $this->assertEquals('this is test add one', $response[0]['name']);
    }


    /**
     * Test hello contoller get data2
     *
     * @return void
     */
    public function testHelloControllerFetchData2()
    {
        $response = $this->get('/api/hellos');
        $response->assertStatus(200);
    }
}