- Lab
-
Libraries: If you want this lab, consider one of these libraries.
- Core Tech
Guided: Testing Your Laravel Application
In this Code Lab, you will enhance your Laravel testing skills through hands-on tasks. You will explore unit and integration testing, safely interact with databases during tests, validate forms, and enforce authorization rules. This lab provides a practical, step-by-step guide with final code solutions for each stage. By the end, you will be equipped to implement robust testing strategies, ensuring reliable and maintainable Laravel applications.
Lab Info
Table of Contents
-
Challenge
Introduction
Welcome to the Guided: Testing Your Laravel Application Code Lab. This lab is designed for web developers and learners eager to enhance their Laravel skills through comprehensive testing practices. You will engage in hands-on tasks, including unit testing, integration testing, database interaction while protecting the primary DB, form and validation testing, and authorization testing. By the end of this Code Lab, you will possess the knowledge and practical experience to implement robust testing strategies in your Laravel applications, ensuring they are reliable, secure, and maintainable. Whether refining your existing projects or embarking on new development challenges, this lab will equip you with the tools to succeed in Laravel testing. Key Takeaways:
-
Learn unit and integration testing in Laravel.
-
Safeguard your primary database during tests.
-
Implement and test form validations effectively.
-
Ensure secure authorization through comprehensive tests. Prerequisites:
-
Foundational PHP Knowledge: Learners should have a basic understanding of PHP, including fundamental concepts like data types, functions, and classes.
-
Basic Laravel Experience: Learners should be familiar with core Laravel features, such as routes, controllers, models, and Blade templates. They should have either built a simple Laravel application or completed a basic Laravel tutorial before this lab.
-
Command-line & IDE Experience: Learners should be able to run commands in the Terminal, including Laravel artisan commands, and be comfortable using an IDE or text editor to work with project files.
__solutionFolder: -
code: The final code for each step is stored in the__solution/codefolder. For instance, the final code for Step 1 is available in the__solution/code/Step01directory. -
images: The folder also contains an image depicting the lab's final state. For example,__solution/images/Step01_final_output.pngcontains the image depicting the final state of Step 1.
-
-
Challenge
Creating a Simple Unit Test
In this initial step, you'll implement a basic
GreetingServiceclass and write a unit test to verify itsgreetmethod. This will introduce you to the fundamentals of unit testing in Laravel and help you ensure that individual components of your application function as expected. Navigate to the first Terminal and run the following command to start the development server:php artisan serve --host=0.0.0.0 --port=8000Once executed, the development server will start, and the application will be accessible for testing at {{localhost:8000}}.
Explanation of the solution above The
GreetingServiceservice has been created for this task, with a function namedgreetthat accepts a$nameparameter and returns a greeting message in the formatHello, {$name}!.Navigate to your second **Terminal** and execute the following command to run only the unit test added above:Explanation of the solution above
The unit test above verifies that the
greetmethod of theGreetingServiceclass returns the expected greeting message. It creates an instance ofGreetingService, calls the greet method with the nameAliceas a parameter, and asserts that the result matchesHello, Alice!.php artisan test tests/Unit/GreetingServiceTest.phpUpon running the test, you should see an output as shown in the example response below indicating that the unit test has passed successfully:
PASS Tests\Unit\GreetingServiceTest âś“ it returns the correct greeting message for a given name 0.01s Tests: 1 passed (1 assertions) Duration: 0.08sinfo> Note: Running the
php artisan testis equivalent to running./vendor/bin/pest. You can use either command.Congratulations! You have successfully created and executed a simple unit test in Laravel. This foundational exercise sets the stage for more advanced testing scenarios and ensures the application's components behave correctly.
-
Challenge
Creating an Integration Test
In this step, you'll complete a
GreetingControllercontroller that utilizes theGreetingServiceto handle the/greetroute and return a greeting message.You'll also write an integration test using
pestto ensure that the endpoint functions are working as expected, helping you understand the basics of integration testing in Laravel.Now, navigate to {{localhost:8000}}/greet?name=Alice to view the GET route. You should see a JSON response with the name `Alice`, as shown in the example response below. Please note that other configurations for creating this route have already been done, as this lab mainly deals with testing.Explanation of the solution above
The `greet` method retrieves the `name` parameter from the URL's query string. If no name is provided, it defaults to "Guest". It then calls the `greet` method from the `GreetingService` to create a greeting message using the retrieved name. Finally, it sends back a JSON response containing the greeting message, making it suitable for API responses.{ "message": "Hello, Alice!" }Explanation of the above solution
The first test verifies that the application responds correctly when a user sends a GET request to the `/greet` route with `Bob` as the `name` parameter. It checks that the server returns a status code of 200, indicating a successful request. It also checks that the JSON response contains `Hello, Bob!`.Now, navigate to your second **Terminal** and execute the following command to run only the unit test added above:Explanation of the above solution
The second test ensures that when no `name` parameter is provided to the `/greet` route, the application defaults to greeting `Guest`. It sends a GET request without specifying a name and checks that the response status is 200. It verifies that the JSON response contains the message `Hello, Guest!` confirming that the application correctly handles cases where the user's name is not supplied by providing a default greeting.php artisan test tests/Feature/GreetingControllerTest.phpUpon running the test, you should see an output as shown in the example response below indicating that the feature test has passed successfully:
PASS Tests\Feature\GreetingControllerTest âś“ it returns the correct greeting message for a given name. 0.11s âś“ it returns a greeting message as Guest when no name is provided. 0.01s Tests: 2 passed (8 assertions) Duration: 0.18sCongratulations! You have successfully created and executed a feature test in Laravel.
-
Challenge
Preventing Tests from Affecting the Primary Database
In this step, you'll configure your Laravel application to use a separate database for tests, ensuring that your primary database remains unaffected.
Explanation of the solution above The above test creates a new task with the title
Navigate to your second **Terminal** and execute the following command to run only the feature test added above:Buy grocery!and asserts that the tasks table contains this task. Since the testing environment uses the primary database, running this test will initially add the task to your main database. which is a bad practice.php artisan test tests/Feature/TaskModelTest.phpYou should see a response in your Terminal, as shown in an example response below:
PASS Tests\Feature\TaskModelTest âś“ it adds a task to the database 0.93s Tests: 1 passed (1 assertions) Duration: 1.28sNavigate to {{localhost:8000}}/tasks and see that
Buy Grocery!is in the list, indicating that the primary database was affected. This is a bad practice, as the test should not affect your primary database. TheRefreshDatabasetrait ensures that your database is reset after each test, preventing data from one test from affecting others. By including the trait in your test class, Laravel automatically wraps each test in a database transaction and rolls back any changes once the test completes. This maintains a clean state for every test, enhancing reliability and preventing interference between tests.The
RefreshDatabasetrait is faster than the other two available traits,DatabaseTruncationandDatabaseMigration.Navigate to your second Terminal and execute the following command to run only the feature test added above:
php artisan test tests/Feature/TaskModelTest.phpUpon running the test, you should see an output as shown in the example response below indicating that the test has passed successfully:
PASS Tests\Feature\TaskModelTest âś“ it adds a task to the database 0.85s Tests: 1 passed (1 assertions) Duration: 1.14sNow, navigate to {{localhost:8000}}/tasks and verify that the "Buy grocery!" item does not appear twice in the list. This confirms that the primary database remains unchanged after configuring the testing environment.
Congratulations! You have successfully isolated the primary database for testing.
-
Challenge
Testing Forms and Validation
In this step, you'll test form submissions with valid and invalid data, check for proper redirection, and confirm that error messages are displayed as expected. Navigate to {{localhost:8000}}/tasks/create and you should see a form that allows you to add new tasks.
Explanation of above solution This test ensures that submitting valid data through the form successfully creates a new task. It simulates a POST request to the `/tasks` endpoint with a valid `title` and `is_completed` status. The test then verifies that the user is redirected to the `/tasks` route, a success message is present in the session, and the new task exists in the database. This confirms that the controller's store method correctly handles and stores valid input.Explanation of above solution
This test verifies that submitting invalid data (an empty title) does not create a task and provides appropriate feedback. It simulates a POST request to the `/tasks` endpoint with an empty title, asserts that the user is redirected back to the task creation form, checks for validation errors in the session, and confirms that no task with an empty title exists in the database. This ensures that validation rules are enforced and prevents invalid data from being stored.Navigate to your second **Terminal** and execute the following command to run only the feature test added above:Explanation of above solution
This test verifies that submitting the form with an empty title triggers validation errors and displays the appropriate message. It simulates a POST request to the `/tasks` endpoint without a title, checks that the user is redirected back to the creation form, and confirms that the error message "The title field is required." is shown. This ensures that the application enforces validation rules and provides clear feedback to users when their input is invalid.php artisan test tests/Feature/TaskCreationFormTest.phpUpon running the test, you should see an output as shown in the example response below indicating that the test has passed successfully:
PASS Tests\Feature\TaskCreationFormTest âś“ it creates a task when valid data is submitted 0.93s âś“ it does not create a task when data is invalid 0.04s âś“ it displays validation errors on the form 0.06s Tests: 3 passed (10 assertions) Duration: 1.31sCongratulations! You created and executed tests for testing forms and their validation.
-
Challenge
Testing Authorization
In this step, you'll implement authorization to ensure that only authenticated users can access the tasks list. You'll update your routes to require authentication, create authorization tests using
pest, and verify that unauthorized users are appropriately restricted. This enhances the security of your application by controlling access to sensitive functionalities. Attaching theauthmiddleware to the/tasksroute ensures only logged-in users can access the tasks list. This prevents unauthorized access and protects sensitive data. The middleware acts as a gatekeeper, checking user authentication before granting access to the route's functionality.Explanation of the above solution
This test ensures unauthenticated users or guests are redirected to the login page when accessing the tasks list. It simulates a GET request to the `/tasks` route without authentication and checks the response redirects to `/login`, preventing unauthorized access.Navigate to your second **Terminal** and execute the following command to run the authorization tests added above:Explanation of the above solution
This test ensures that authenticated users can see the task list and successfully access it. It creates a user using a factory, authenticates as that user, and simulates a GET request to the
/tasksroute. It confirms that the response status is 200, indicating successful task list access.php artisan test tests/Feature/TaskAuthorizationTest.phpBy executing the
TaskAuthorizationTesttests, it can be verified that the authorization rules for accessing the tasks list are properly enforced. A successful test run will confirm that guests are redirected to the login page and that authenticated users can access the tasks without issues.You should see a response in your Terminal, similar to the example below, confirming that the feature test has been added and is working successfully:
PASS Tests\Feature\TaskAuthorizationTest âś“ it ensures guests cannot see the task list 0.17s âś“ it ensures authenticated users can see the task list 0.03s Tests: 2 passed (3 assertions) Duration: 0.27sCongratulations! You've successfully implemented authorization tests in your Laravel application.
About the author
Real skill practice before real-world application
Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.
Learn by doing
Engage hands-on with the tools and technologies you’re learning. You pick the skill, we provide the credentials and environment.
Follow your guide
All labs have detailed instructions and objectives, guiding you through the learning process and ensuring you understand every step.
Turn time into mastery
On average, you retain 75% more of your learning if you take time to practice. Hands-on labs set you up for success to make those skills stick.