Starting a new TDD Laravel project

My personal Laravel quickstart, for a Laravel project with test driven development.

Published: 24-11-2019

This post is not intended to be a detailed guide, or even to be very usable for other people. It is my own note to myself, as I start to learn Laravel, to try and keep the various concepts and components of a Laravel project clear in my own head.

Installation

Review the installation guide. You should use the Laravel Homestead virtual machine, or Docker, or something. If you're impatient (like me), or fed up of wrestling with VMs that don't work nearly as smoothly as they're supposed to (also like me), and want to start coding without learning basic devops first, then you can:

  • Install PHP 7.2.x +.
  • Install Composer.
  • Install Laravel with composer global require laravel/installer.
  • Check your php.ini. Confirm the following are present, and enabled:
    • BCMath PHP Extension
    • Ctype PHP Extension
    • JSON PHP Extension
    • Mbstring PHP Extension
    • OpenSSL PHP Extension
    • PDO PHP Extension
    • Tokenizer PHP Extension
    • XML PHP Extension

Note: if you get errors when working through the quickstart, check that everything you installed is added to your PATH, and double check your php.ini.

Quickstart

Create a new Laravel project:

laravel new <projectName>

Tests

Laravel uses PHPUnit for testing. Create a feature test:

php artisan make:test <TestName>

The convention is to call tests <Name>Test. For example, MyTest.

Note: to run tests with phpunit <TestName>, install PHPUnit globally with composer global require phpunit/phpunit.

.env and phpunit.xml

Add your database information to the .env file. Refer to the docs for additional guidance.

You don't want your tests to mess with your database. Modify phpunit.xml to use a separate database for testing. Add the following to the <php> object:

    <server name="DB_CONNECTION" value="sqlite"/>
    <server name="DB_DATABASE" value=":memory:"/>

Migrations

Migrations create, update, and destroy tables in the database. You need one migration per table. Using migrations allows you to quickly recreate the database structure (especially useful when testing).

php artisan make:migration create_<name>_table

Models

Each database table needs a corresponding model. All interactions with the table occur through the model. Using the model layer allows us to use Eloquent queries.

php artisan make:model <Name>

Controllers

You can manage all requests in the routes files (API requests, page requests and so on) However, it's better to use a controller. Using a controller grants access to convenience features such as the middleware, validate and auth methods.

php artisan make:controller <ControllerName>

The convention is to call controllers <Name>Controller. For example, MyController.

Route files

Modify the appropriate route file to direct requests to the controller. For example, to load a page, add the following to your routes/web.php file:

Route::get('/<page>', '<ControllerName>@index');

When a user hits root/<page> Laravel calls the index() method in the <Name>Controller.php file. In this example, the controller will then return a view. However, you use the same basic logic if you want to interact with a database or call an API endpoint.

Factories

Laravel factories allow you to build fake data for your models, to use in your tests. Create a new factory and associate it with your model:

php artisan make:factory <FactoryName> --model="App\<Model>"

The convention is to call factories <Name>Factory. For example, MyFactory.

Use your factory in your tests, or use it with Tinker to add dummy data to your development database. The following creates five dummy records:

php artisan tinker
factory(`App\<Model>`, 5)->create();

Version control

Don't forget to set up version control. New Laravel projects automatically have a .gitignore, so all you need to do is create a new remote repository, then:

git init
git remote add origin <your remote repo>

Note: if you already have things in your remote repository (for example, you created it with a README), git pull --allow-unrelated-histories is your friend.