In this article, I will show you how to build a REST API application with Test-Driven Development using laravel framework.
What is Test-Driven Development?
TDD (Test Driven Development) is a software development method where programming, testing and design activities are intertwined.
Rules of TDD:
- Writing a unit test to describe one side of the program, the recently written test often fails because that feature is not yet installed.
- Write just enough code to pass the test
- Refactor the code until it meets the criteria of the simple code.
- Repeat the above operation
1. Install the project
Create a laravel project
composer create-project –prefer-dist laravel / laravel tdd-laravel.
Next, run 2 commands:
php artisan make: auth
and
php artisan migrate.
final initialization step we delete files ExampleTest.php
in 2 directory tests/Unit
and tests/Feature
2. Write code for the registration function
- Configuration in
config/auth.php
file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token single-quoted-string string">'defaults'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'guard'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'api'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'passwords'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'users'</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'guards'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token punctuation">[</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token single-quoted-string string">'api'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'driver'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'jwt'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'provider'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'users'</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> </span> |
- Create routes in
routes/api.php
1 2 3 4 5 6 7 | <span class="token php language-php"><span class="token delimiter important"><?php</span> Route <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">group</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'middleware'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'api'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'prefix'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'auth'</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> Route <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">post</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'authenticate'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">' <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> '</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">name</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'api.authenticate'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> Route <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">post</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'register'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">' <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> '</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">name</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'api.register'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> </span> |
- In the User.php model
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token keyword">class</span> <span class="token class-name">User</span> <span class="token keyword">extends</span> <span class="token class-name">Authenticatable</span> <span class="token keyword">implements</span> <span class="token class-name">JWTSubject</span> <span class="token punctuation">{</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getJWTIdentifier</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">getKey</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getJWTCustomClaims</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
- Create controller AuthController.php with the command
php artisan make: controller AuthController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token keyword">class</span> <span class="token class-name">AuthController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">authenticate</span> <span class="token punctuation">(</span> Request <span class="token variable">$request</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//Validate fields</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">validate</span> <span class="token punctuation">(</span> <span class="token variable">$request</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'email'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'required|email'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'password'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'required'</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">//Attempt validation</span> <span class="token variable">$credentials</span> <span class="token operator">=</span> <span class="token variable">$request</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">only</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'email'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'password'</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token operator">!</span> <span class="token variable">$token</span> <span class="token operator">=</span> <span class="token function">auth</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">attempt</span> <span class="token punctuation">(</span> <span class="token variable">$credentials</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">response</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'error'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'Incorrect credentials'</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token number">401</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token function">response</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token function">compact</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'token'</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">register</span> <span class="token punctuation">(</span> Request <span class="token variable">$request</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//Validate fields</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">validate</span> <span class="token punctuation">(</span> <span class="token variable">$request</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'email'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'required|email|max:255|unique:users'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'name'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'required|max:255'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'password'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'required|min:8|confirmed'</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// tạo mới user, tạo ra token và trả về</span> <span class="token variable">$user</span> <span class="token operator">=</span> User <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">create</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'name'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token variable">$request</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">input</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'name'</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'email'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token variable">$request</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">input</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'email'</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'password'</span> <span class="token operator">=</span> <span class="token operator">></span> Hash <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">make</span> <span class="token punctuation">(</span> <span class="token variable">$request</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">input</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'password'</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$token</span> <span class="token operator">=</span> JWTAuth <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">fromUser</span> <span class="token punctuation">(</span> <span class="token variable">$user</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">response</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token function">compact</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'token'</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
In this step, we will add 2 methods (functions): authenticate () and register () methods. In the authenticate method, we authenticate the email and password. In the register method, we validate the input, create a new user with and create a token and then notify the user.
- To test what we’ve just written above, create the AuthTest class to test it
run the command
php artisan make: test AuthTest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token comment">/** * @test * Test registration */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">testRegister</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//User's data</span> <span class="token variable">$data</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'email'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">' <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> '</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'name'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'Test'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'password'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'secret1234'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'password_confirmation'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'secret1234'</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token comment">//Send post request</span> <span class="token variable">$response</span> <span class="token operator">=</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'POST'</span> <span class="token punctuation">,</span> <span class="token function">route</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'api.register'</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token variable">$data</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">//Assert it was successful</span> <span class="token variable">$response</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">assertStatus</span> <span class="token punctuation">(</span> <span class="token number">200</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">//Assert we received a token</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">assertArrayHasKey</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'token'</span> <span class="token punctuation">,</span> <span class="token variable">$response</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">//Delete data</span> User <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">where</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'email'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">' <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> '</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">delete</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/** * @test * Test login */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">testLogin</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//Create user</span> User <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">create</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'name'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'test'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'email'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">' <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> '</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'password'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token function">bcrypt</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'secret1234'</span> <span class="token punctuation">)</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">//attempt login</span> <span class="token variable">$response</span> <span class="token operator">=</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'POST'</span> <span class="token punctuation">,</span> <span class="token function">route</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'api.authenticate'</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'email'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">' <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> '</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'password'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'secret1234'</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">//Assert it was successful and a token was received</span> <span class="token variable">$response</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">assertStatus</span> <span class="token punctuation">(</span> <span class="token number">200</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">assertArrayHasKey</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'token'</span> <span class="token punctuation">,</span> <span class="token variable">$response</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">//Delete the user</span> User <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">where</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'email'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">' <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> '</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">delete</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> </span> |
Now, to check whether the above test results are correct, we use the command $vendor/bin/phpunit
or $ phpunit
. If the data case is not ideal then we need to look at the log and correct it.
Conclude
Through this article we can better understand the concept of TDD (Test-Driven Development) and the steps to implement TDD for a project using the Laravel Framework.