First steps with Laravel and Continuous Delivery

First steps with Laravel and Continuous Delivery

Laravel is currently the most popular PHP framework. The numbers cannot lie: over 65k followers on Twitter, 30k stars and 10k forks on GitHub. This guide will show how to create a Continuos Delivery pipeline for an application built with Laravel.

Hint

Actions used in this guide:

Laravel-based application

In the first part of the article, we'll discuss the process of creating a demo project (on the example of a simple calculator) for which we'll create unit and feature tests.

Hint
If you're familiar with Laravel's basics you can skip this part and jump right ahead to setting Laravel CI with Buddy.

Install Laravel

First, you need to install these things locally:

  1. PHP v. 5.6.4 or newer: http://php.net/manual/en/install.php
  2. PHP Composer: https://getcomposer.org/doc/00-intro.md
Hint
This project requires extenstions for PHP MBstring and DOM. Here's an example installation for PHP 7.0: $ apt-get install php7.0-mbstring php7.0-dom

With everything in place, we're ready to install Laravel:

default
$ composer global require "laravel/installer"

The last thing to do is adding Laravel to PATH environment variable so that our app can be executed with the laravel command:

default
$ export PATH="$PATH:$HOME/.config/composer/vendor/bin"

Initialize application with Laravel framework

Now we can create a new application using Laravel. Let's call it my_calc:

default
$ laravel new my_calc

This command will create a new directory for the project and initiate the Laravel framework in it.

Application description

The application will be a simple calculator, so the first thing we need to do is to define the class with methods for adding, subtraction, mutliplication, and division.

Create a file app/Calculator.php and paste the following template:

php
<?php namespace App; class Calculator { public function sum($x, $y) { $z = $x + $y; return $z; } public function diff($x, $y) { $z = $x - $y; return $z; } public function multiplication($x, $y) { $z = $x * $y; return $z; } public function div($x, $y) { if($y == 0) return "don't divide by zero"; $z = $x / $y; return $z; } }

Define Routing

In the application's directory you'll find the folder Routes with four files in which we define the views for our app. Since the app is web-based, we shall define the list of views in theweb.php file. Let's define two views, the calculator's form and the results:

default
Route::get('/', 'CalcController@home'); Route::post('/calc', 'CalcController@calc');

The logic of the routing will not be coded in this file—we'll do it in the Controller's class instead.

Configure Controller

Most modern frameworks introduce the concept of controllers, which make maintenance, testability and expansion of the application easier by taking control over its requests.

To initiate Controller, run:

default
php artisan make:controller CalcController

Artisan will create a Controller class in this location:

default
app/Http/Controllers/CalcController.php

In this class, we'll define two public functions that we used in routs/web.php. On top of that, we shall add a private render function which will generate the HTML for each view. In the render method we shall use the previously defined Calculator class:

php
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Calculator; class CalcController extends Controller { public function home() { return $this->render(); } public function calc(Request $request) { return $this->render($request->all()); } private function render($items = null) { $c = new Calculator(); if (is_array($items) && isset($items['a']) && isset($items['b']) && isset($items['action'])){ $action = $items['action']; $a = floatval($items['a']); $b = floatval($items['b']); if ($action == '+'){ $result = $c->sum($a, $b); }else if ($action == '-'){ $result = $c->diff($a, $b); }else if ($action == '*') { $result = $c->multiplication($a, $b); }else{ $result = $c->div($a, $b); } $items['result'] = $result; }else{ $items = array( 'a' => '', 'b' => '', 'action' => '+', ); } return view('calc', $items); } }

Blade Template

All that remains is defining the of view of the calc template. We'll do that with the Blade template engine which is added to the Laravel framework on default.

Add the file resources/views/calc.blade.php with the following content:

Hint
html
<form action="/calc" method="post" > {{ csrf_field() }} <input placeholder="A" value="{{ $a }}" name="a" /> <select name="action"> <option @if ($action == '+') selected="selected" @endif>+</option> <option @if ($action == '-') selected="selected" @endif>-</option> <option @if ($action == '*') selected="selected" @endif>*</option> <option @if ($action == '/') selected="selected" @endif>/</option> </select> <input placeholder="B" value="{{ $b }}" name="b" /> @if (isset($result)) <strong>= {{ $result }}</strong> @endif <button>Execute</button> </form>

Run Laravel application

Now we're ready to test if our calculator works properly. Again, we can use Artisan for that and its built-in http server:

default
php artisan serve

This function will launch an HTTP server and generate the url to the website. Copy the URL and paste it in your browser:


Laravel tests

In this part of the guide we'll show you how to test a Laravel application with PHPUnit. Starting with v5.3, Laravel supports three types of tests:

  • Unit tests
  • Feature tests
  • Browser tests

You will learn how to write tests for each type of tests on an example of a preset application: github.com/buddy-works/laravel-first-steps.

Hint
If you know the basics of creating Laravel tasks, you can jump ahead directly to test automation with Buddy.

Unit tests

Unit tests are used to check small chunks of code, usually individual methods. Go to your terminal and execute this command in the directory with your Laravel project:

default
php artisan make:test MyFirstUnitTest --unit

This will create a file tests/Unit/MyFirstUnitTest.php. Let's create some tests for the Calculator class:

php
<?php namespace Tests\Unit; use Tests\TestCase; use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\DatabaseTransactions; use App\Calculator; class MyFirstUnitTest extends TestCase { public function testSum() { $calculator = new Calculator(); $this->assertTrue($calculator->sum(2, 2) == 4); } public function testDiff() { $calculator = new Calculator(); $this->assertTrue($calculator->diff(2, 2) == 0); } public function testMultiplication() { $calculator = new Calculator(); $this->assertTrue($calculator->multiplication(2, 2) == 4); } public function testDiv() { $calculator = new Calculator(); $this->assertTrue($calculator->div(2, 2) == 1); } public function testDivByNull() { $calculator = new Calculator(); $this->assertTrue($calculator->div(2, 0) == "don't divide by zero"); } }

You can run unit tests with the following command:

default
$ vendor/bin/phpunit

Feature tests

Feature tests are used to examine larger parts of code. For example, you can define tests that will create an HTTP client that will request the URL of your website and check its contents. To do that, go to your project and execute:

default
php artisan make:test MyFirstFutureTest

The command will create a file tests/Feature/MyFirstFutureTest.php where you can define the tests for the views:

php
<?php namespace Tests\Feature; use Tests\TestCase; use Illuminate\Foundation\Testing\WithoutMiddleware; use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\DatabaseTransactions; class MyFirstFutureTest extends TestCase { public function testHomePage() { $response = $this->get('/'); $response->assertStatus(200); } public function testCalcPage() { $array = array( "a" => "4", "b" => "0", "action" => "/", ); $response = $this->post('/calc', $array); $response->assertStatus(200); $response->assertSee("don&#039;t divide by zero"); } }

Feature tests are triggered the same way as unit tests:

default
$ vendor/bin/phpunit

Browser Tests - Laravel Dusk

Browser tests are a type of integration tests. They launch a browser and physically interact with the website content. Here's an example test that will check the adding operation in our calculator:

php
public function testExample() { $this->browse(function ($browser) { $browser->visit('/') ->type('a', 3) ->type('b', 1) ->press('Execute') ->assertPathIs('/calc') ->assertSee('4'); }); }

This type of tests is a bit different and more complicated than unit and feature tests. They are explained in detail in our Laravel Dusk guide.


Automating Laravel tests with Buddy

In the previous steps, we discussed how to configure and test a Laravel project. In this part of the article, we'll show you how to automatically trigger the tests on every push to the repository using Buddy CI/CD, and further expand the pipeline.

For the purpose of this guide, we've created a Laravel project with tests already configured in the repository. You can fork it from here: github.com/buddy-works/laravel-first-steps

  1. Create a new project, choose GitHub as the provider, and select the forked repository:
    Image loading...Selecting the repository

  2. Add a new pipeline, set the trigger mode to On every push and select Master as the target branch:
    Image loading...Adding a new pipeline

  3. Add the PHPUnit action and enter the commands that will trigger the tests:

    default
    composer install vendor/bin/phpunit

Image loading...Configuring the PHP action

  1. Click Add this action when ready
Warning
Before running the command, make sure you have the .env file with the application encryption key. If you added the file to .gitignore, use a template and copy it at the beginning of the action.

From now on, every time you'll make a push to the Master branch, Buddy will execute the tests configured in the repository. You can also run the pipeline manually.

Auto-deployment

With the application properly tested, you can expand your delivery process by adding a deployment action to your type of server after the PHP action.

  1. Go to the Laravel pipeline and click Manage actions in this pipeline
  2. Add file transfer action below the PHP action:
    Image loading...Adding the FTP action
  3. Provide the details to your server
  4. Click Add this action when ready

Now, make a push to your repository and watch Buddy test and deploy your app to the server.

Congratulations! You have just streamlined the whole process down to a single push to the repository by introducing Continuous Delivery to your workflow.

Jarek Dylewski

Jarek Dylewski

Customer Support

A journalist and an SEO specialist trying to find himself in the unforgiving world of coders. Gamer, a non-fiction literature fan and obsessive carnivore. Jarek uses his talents to convert the programming lingo into a cohesive and approachable narration.