Writing testable API apps in Slim framework

Editor’s Note: This is a repost of a Medium post by Oyebanji Jacob, an Andela developer who’s currently using Node, React and Redux to build out an internal application for engineering team management. Oyebanji is especially interested in big data and code refactoring, and when he’s not coding, you can find him playing or watching football.

Slim is an awesome and fast framework for building APIs in PHP.

In order to fulfill one of the requirements for becoming a PHP web developer at Andela, we are required to write an API service for emojis using Slim framework. After reading a lot of blogs and going through the official documentation on the website, I set out to build the app as required.

But there was a problem: I needed to be able to test my app and all the tutorials I’ve read did not introduce me to testing Slim apps. When I googled for answers on how to test Slim apps, I found hints and approaches for writing testable apps, but nothing that was detailed enough for me to understand how to test my unbuilt app.

Note: Writing testable apps with good test cases is a core requirement at Andela. Your App is not good for review if you have not written tests.

Below, I’ll demonstrate how you can test your apps written using Slim framework using a very simple example.

In this tutorial, we will be writing an API that sends simple responses to various requests on a Todo object.

App Setup

  • Make and change our current directory to our Todo API folder
mkdir SlimTodo && cd SlimTodo
  • Create a composer file for the project

For this project, this is the content our base composer file.

  • Install Slim

We install slim by running

composer require slim/slim "^3.0"

This installs composer and its dependencies and inside the vendor folder and updates our composer.json file to include slim as a dependency for the project.

  • Create public/index.php file

Following best practises, we create a folder, public, a simple file, index.php, to house our setup code.

The above is just a simple route definition for the / or index route.

To see this in action, from the SlimTodo folder, run

php -S 127.0.0.1:8080 -t public

Then visit http://127.0.0.1:8080 on your browser.

You should see “Hello, Todo” as a response.

Good!!!

Routes

Like I said earlier, this project is meant to create a very Todo API with simple responses and write basic tests for the endpoints

Here are the endpoints and the responses.

Request Type: GET
Endpoint: /todo
Status: 200
Response: “Hello, Todo”
Request Type: GET
Endpoint: /todo/:id
Response status: 200 or 404
Response: “Todo :id” or “Todo Not Found”
Request Type: POST, PUT, PATCH
Endpoint: /todo/:id
Response status: 200 or 404
Response: “Todo :id, updated successfully” or “Todo Not Found”
Request Type: DELETE
Endpoint: /todo/:id
Response status: 200 or 404
Response: “Todo :id, deleted successfully” or “Todo Not Found”

Let’s update our index.php to include these routes and responses.

Setup for Testing

First, we include PHPUnit as the a development dependency in our app.

To do that, we update our composer.json file.

Then, we run

composer update

We’ll be creating a folder, test, to contain our tests.

mkdir test

In the test directory, create a new file named TodoTest.php and copy this as its content

Let’s run PHPUnit against TodoTest.php to ensure we have the correct setup

./vendor/bin/phpunit ./test/TodoTest.php

You should see something related to this as output

PHPUnit 5.4.8 by Sebastian Bergmann and contributors.
.                                                      1 / 1 (100%)
Time: 45 ms, Memory: 3.25MB
OK (1 test, 1 assertion)

Our testing setup is good!!!

Testing our API endpoints

We now have our test suite ready but we have an issue.

How do we test the app?

This was the first question I pondered over while setting out for my project.

But there is an issue with our current app setup. For our app to be testable we need to get the instance of the app before we call the run method which bootstraps the app for web requests.

Let’s refactor our index.php file.

First, let’s create a new folder, src, to house our app class.

mkdir src

Secondly, we create a new file, App.php, in src directory and move some part of our index.php code into it.

Because of the new namespace, Pyjac, we just included in our app, we need to update our composer.json file to inform composer on how to autoload files in the src directory.

To let composer be aware of our changes, we run

composer dump-autoload

Our slimmed down version of index.php is now

With this, we can now create an instance of our app and pass in test requests to the app to simulate API calls.

Let’s test GET request to the app. To do this, we make use of theSlim\Http\Environment class to mock HTTP headers and build up the Request object from the headers using Slim\Http\Request.

Notice how we called $this->app->run(true). This tells Slim to run the app instance and instead of return HTTP headers and echoing the body of the response it should return an object.

Run the test

./vendor/bin/phpunit ./test/TodoTest.php

You should have a result similar to this

PHPUnit 5.4.8 by Sebastian Bergmann and contributors.
.                                                      1 / 1 (100%)
Time: 51 ms, Memory: 4.50MB
OK (1 test, 2 assertions)

Congrats, we’re just written our first API test that hits an endpoint in our app and validate the correctness of the status code and the response body.

Let’s test other endpoints.

Let’s test GET request to /todo

For POST request to /todo/{id}

Note: You can use the same pattern for PUT and PATCH

For DELETE request /todo/{id}

Putting all together

Thank you for reading :)


Check out Oyebanji’s Github repo to understand how he implemented Slim in his project.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.