18:58:36 8/5/2024 - 15 views -
Programming

Laravel testing

In Laravel, it has 2 test types:

  • ​Unit test
  • Feature test

Unit test only focuses on a small piece of code (usually a method inside a class), while a feature test verifies if a particular feature, which may consist of multiple methods or classes interacting with each other, is working the way you designed.

Create tests

​- Create a feature test

php artisan make:test UserTest

​- Create a unit test

php artisan make:test UserTest --unit

Get started

​To get familiar with the Laravel test, when you run one of the two commands above to create a test, Laravel will create a folder with the structure like this:

​tests


​___Feature

​  |___ExampleTest.php

​  |___UserTest.php

​___Unit

​  |___ExampleTest.php


​Okay, I can run this command to get started on the tests:

./vendor/bin/phpunit

​The output will show the message that is well for all tests.

​Now, I will edit something in UserTest.php:

public function test_example(): void
{
    $x = 1 + 1;
    $this->assertTrue($x == 3);
}

​If you run tests, you will receive an error at the test_example() function, because the result of the calculation is 2, it is not 3

Call API

​There are 2 ways to send a request (call API):

​1. withHeaders

$response = $this->withHeaders([
    'Accept' => 'application/json',
    'Content-Type' => 'application/json',
    'Authorization' => 'Bearer ' . $jwtToken,
])->json('POST', '/endpoint');

$this->assertEquals(200, $response->status());

​2. postJson

$headers = ['Authorization' => 'Bearer ' . $jwtToken];
$response = $this->postJson('/personal/upload-image-editor', [], $headers);
$this->assertEquals(200, $response->status());

Test dependencies

​Usually, the testing will run from the top to the bottom ordering, but in the case your function is async and you want to ensure the order is exact, you can use @depends annotation.

​For example, if you have a test with 2 cases:

  1. Create a user 
  2. Delete the user just created

​If you create 2 functions to do this, perhaps the delete method will run before the create method so you will receive an error.

To prevent this, PHPUnit supports test dependencies via the @depends annotation.

public function createUser(){}
/**
* @depends testEmpty
*/
public function deleteUser(){}

​The code above will ensure the createUser function will execute finished, after that, the deleteUser function will execute

​Run tests

​Run all tests:
php artisan test

​or

./vendor/bin/phpunit
​Run all tests and display details of the error if it has:
./vendor/bin/phpunit --testdox
​Run a specific test file:
./vendor/bin/phpunit --testdox .\tests\Feature\UserTest.php

Or you can run directly in VS Code (Image 1)

Run a specific file to test in VS Code
Image 1: Run a specific file to test in VS Code
Run a specific test file and a specific function:
./vendor/bin/phpunit --testdox .\tests\Feature\UserTest.php --filter createUser

But with the example above, if you want to run a specific function that depends on another function, it will be an error.

​Or you can run a specific function directly VS Code (Image 2)

Run a method to test in VS Code
Image 2: Run a method to test in VS Code

Get data from the response

​For example, We call the API to the server that returns a JSON:

class myController{
	function test()	
	{
		return response()->json(['message' => 'Hello']);
	}
}

​testing:

function test_get_message()
{	
	$response = $this->postJson('/test');
	$this->assertEquals(200, $response->status());
	$res= $response->json();
	$message = $res['message'];
}

​Pass values between tests (function)

In PHPUnit, every test independent, meaning is the variables of every test (function) which will not be shared with each other. 

​To share the variables with each other, it must depend on using @depends, see the example following:

public function test_create_post()
{
	$id_post = 1;
	return $id_post;
}
/**
* @depends test_create_post
*/
public function test_delete_post_illegal($id_post): void
{
	//$id_post = 1
}
/**
* @depends test_create_post
*/
public function test_delete_post_legal($id_post): void
{
	//$id_post = 1
}

​References

​https://betterstack.com/community/guides/testing/laravel-unit-testing/