Hamburger Icon
  • Labs icon Lab
  • Core Tech
Labs

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.

Labs

Path Info

Level
Clock icon Intermediate
Duration
Clock icon 25m
Published
Clock icon Jan 10, 2025

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Table of Contents

  1. 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. __solution Folder:

    • code: The final code for each step is stored in the __solution/code folder. For instance, the final code for Step 1 is available in the __solution/code/Step01 directory.

    • images: The folder also contains an image depicting the lab's final state. For example, __solution/images/Step01_final_output.png contains the image depicting the final state of Step 1.

  2. Challenge

    Creating a Simple Unit Test

    In this initial step, you'll implement a basic GreetingService class and write a unit test to verify its greet method. 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=8000
    

    Once executed, the development server will start, and the application will be accessible for testing at {{localhost:8000}}.

    Explanation of the solution above

    The GreetingService service has been created for this task, with a function named greet that accepts a $name parameter and returns a greeting message in the format Hello, {$name}!.

    Explanation of the solution above

    The unit test above verifies that the greet method of the GreetingService class returns the expected greeting message. It creates an instance of GreetingService, calls the greet method with the name Alice as a parameter, and asserts that the result matches Hello, Alice!.

    Navigate to your second **Terminal** and execute the following command to run only the unit test added above:
    php artisan test tests/Unit/GreetingServiceTest.php
    

    Upon 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.08s
    

    info> Note: Running the php artisan test is 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.

  3. Challenge

    Creating an Integration Test

    In this step, you'll complete a GreetingController controller that utilizes the GreetingService to handle the /greet route and return a greeting message.

    You'll also write an integration test using pest to ensure that the endpoint functions are working as expected, helping you understand the basics of integration testing in Laravel.

    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.
    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.
    {
        "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!`.
    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.
    Now, navigate to your second **Terminal** and execute the following command to run only the unit test added above:
    php artisan test tests/Feature/GreetingControllerTest.php
    

    Upon 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.18s
    

    Congratulations! You have successfully created and executed a feature test in Laravel.

  4. 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 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.

    Navigate to your second **Terminal** and execute the following command to run only the feature test added above:
    php artisan test tests/Feature/TaskModelTest.php
    

    You 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.28s
    

    Navigate 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. The RefreshDatabase trait 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 RefreshDatabase trait is faster than the other two available traits, DatabaseTruncation and DatabaseMigration.

    Navigate to your second Terminal and execute the following command to run only the feature test added above:

    php artisan test tests/Feature/TaskModelTest.php
    

    Upon 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.14s
    

    Now, 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.

  5. 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.
    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.
    Navigate to your second **Terminal** and execute the following command to run only the feature test added above:
    php artisan test tests/Feature/TaskCreationFormTest.php
    

    Upon 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.31s
    

    Congratulations! You created and executed tests for testing forms and their validation.

  6. 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 the auth middleware to the /tasks route 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.
    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 /tasks route. It confirms that the response status is 200, indicating successful task list access.

    Navigate to your second **Terminal** and execute the following command to run the authorization tests added above:
    php artisan test tests/Feature/TaskAuthorizationTest.php
    

    By executing the TaskAuthorizationTest tests, 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.27s
    

    Congratulations! You've successfully implemented authorization tests in your Laravel application.

Asmin Bhandari is a full stack developer with years of experience in designing, developing and testing many applications and web based systems.

What's a lab?

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.

Provided environment for hands-on practice

We will provide the credentials and environment necessary for you to practice right within your browser.

Guided walkthrough

Follow along with the author’s guided walkthrough and build something new in your provided environment!

Did you know?

On average, you retain 75% more of your learning if you get time for practice.