Part 1: Testing Model Relationships in Laravel — Schema Tests

tonyfrenzy profile image tony Originally published at Medium on ・6 min read

Part 1: Testing Model Relationships in Laravel — Schema Tests

Laravel Database Designer — Biodesign.cc

Laravel makes TDD a lot more fun, it is such a joy to work with . The essence of the tests in this series is to ensure that your app model relationship is not missing a bolt. The code snippets will be available for easy reach at this Github project link.

Table of contents

To make this post more organized it will be split into three (3) parts.

Writing tests make your code rock solid, predictable and highly maintainable. I have written some terrible apps in the past and it can be unnerving when broken codes scream in — y o u r — face. Those years I had no clue about unit tests — fix one bug and another one surfaces, more annoying is that you don’t know when another will pop up. Errors are bound to occur if relevant models are missing or wrongly connected.

Unit and Feature Tests

Unit Tests are written for small pieces of a code base such as methods or attributes in a class. It usually deals with testing fine details at low level only. In our case we will be testing some methods on Laravel model classes, that is, model connections and relationships between different parts of an app.

Feature Tests is more encompassing as it sums up different part of a code and tests how well they inter-operate eg functional tests and integration tests on components, modules etc. We are not going into functional test in this post.

NB: it is assumed that you have a working knowledge of Laravel, therefore nitty gritty of installation, eloquent model setup and relationship are not discussed. However, test relevant topics will be discussed in depth.

To install a new laravel app :

  • laravel new modelRelTests via installer
  • composer create-project --prefer-dist laravel/laravel modelRelTests via create-project

1. Set Up Test Suite

We are going to make use of an sqlite database and use it in memory for faster test runs. Go to phpunit.xml at the root directory of your application and add:

<server name=" **DB\_CONNECTION**" value=" **sqlite**"/>
<server name=" **DB\_DATABASE**" value=" **:memory:**"/>

2. Creating a Test Class

If we run vendor/bin/phpunit at this point we get 2 tests for the dummy tests added by Laravel, one test each in the Unit and Feature test directories. Seeing the green is refreshing. You should delete the two files in preparation for our real tests.

By default, every new Laravel installation comes with a User model class (along with migration, controller etc) but not a test. We should create our own test file with the command:

php artisan make:test **UserTest --unit**

This creates a test file named UserTest.php within the tests/Unit directory in the root folder. The --unit flag implies that we are creating a unit test and should add the generated file to the unit test directory. Without the --unit flag we have a feature test and it gets added to tests/Feature directory.

3. Schema Test — My First Test in Every Model

Before visiting model relationship tests, my very first unit test in every Laravel model is the schema test. We can use this test to ensure that relevant table columns are not missing and also have the correct and expected names. All we need to do is this:

Take note of :

  • use Illuminate\Support\Facades\Schema; namespace.
  • RefreshDatabase and WithFaker traits. These two traits are important in most tests since you will most likely need a database of data to test your models and the faker library to populate a database with data to be tested upon.

If you want to be explicit about your schema checks you may check each individual field with:

  • ...Schema:: **hasColumn** ('model', **'column'** ), 1); instead of
  • ...Schema:: **hasColumns** ('model', **['column\_1', 'column\_2']**), 1); which checks all columns existence at once.

I prefer **hasColumns()** though, odd part is that you get a general error report and so don’t know the actual column affected unless you check thoroughly.

Run vendor/bin/phpunit and see the result below 👇

TDD — failed because database is not set

This test failed, why? We have not set up or created our database yet. Set up your database configurations within the .env file according to your machine. See the snippet below:


Then, create your database within your xampp, wamp or homestead and run:

$ php artisan migrate

Illuminate\Database\QueryException : SQLSTATE[42000]: If you encounter the Illuminate\Database\QueryException : SQLSTATE[42000] error while running the migration like in image below


Go to App/Providers/AppServiceProvider.php and make the following updates. Within the boot method add Schema::defaultStringLength(191); and add a the namespace like so use Illuminate\Support\Facades\Schema;. See below 👇

Fix Illuminate\Database\QueryException : SQLSTATE[42000] error.

Run vendor/bin/phpunit again and you should get a success result as below:

Test Result Successful!

Play around a little more by adding a new column into the test, do not add to the schema migration file initially, run the test to see results, failed? Make it pass. This particular test may look boring but from the ground up you can be sure your schema integrity is accounted for.

4. Creating Aliases for Your CLI Commands

Now that you are beginning to write tests there will be a lot of tests to run. It would make much sense to have shortcut form of some lengthy commands, the cli commands you use often. This will surely improve your productivity. Bash alias es to the rescue, it is a method of supplementing or overriding Bash commands with new ones eg allow users to customize their experience in a POSIX terminal.

  • alias name="command to shorten"  — creates a new alias ‘name’ NB: there are no spaces around the = sign.
  • alias  — displays all your set aliases directly in the CLI.
  • On a Windows PC, you may access and manage a list of your set aliases in the .bash_profile file at C:\Users\yourUsername\.bash\_profile. Here you can add, update or remove the entries.

I use the commands below most times in my tests:

  • pu vendor/bin/phpunit this runs all tests within the tests directory.
  • puf vendor/bin/phpunit --filter this selectively runs test within all files and test methods whose name has the string (pattern).
  • putu vendor/bin/phpunit --testsuite Unit this runs all tests within the Test\Units directory only.
  • putf vendor/bin/phpunit --testsuite Feature this runs all tests within the Test\Features directory only.

There are more others but these ones comes handy for me all the time.


I become paranoid if I write an app without some tests these days. I learnt the hard way and has since inculcate the habit of writing comprehensive tests for my apps — the predictability, ease of maintenance and confidence that accompanies a well tested codebase is indescribable. Kindly check the remaining two parts (see links below 👇) for they are the biggest deal.

Your comments are highly appreciated.

Posted on by:

tonyfrenzy profile



Web Software Developer. NodeJs | Laravel | VueJs | SEO.


markdown guide

Thanks for breaking down the diff between unit and feature. I recently adopted TDD and i am now more confident in my code