
Laravel is a popular PHP framework known for its easy-to-learn syntax, modular and scalable architecture, and extensive ecosystem of tools and libraries. It emphasizes security with built-in features for encryption, hashing, validation, and more. With a clean and concise syntax, Laravel makes code readable and enjoyable for developers, and utilizing Laravel's testing framework can greatly improve the development process and reduce bugs in large projects. Whether implementing test coverage from the beginning or retroactively, having tests in place is crucial for efficient development and bug-free applications.
This course will focus on building backend applications with Laravel, specifically exploring architecture layers and separating framework layers (controllers, jobs, notifications, validation, etc.) from the business layer (services, actions, use cases, etc.). Topics covered will include creating a maintainable test suite, testing asynchronous features like notifications and queues, working with timezones, and testing integration with popular Laravel packages like Sanctum, Passport, Socialite, and Scout. Additionally, an introduction to CI/CD automation for testing with GitHub, Gitlab, and Bitbucket will be provided.
This course is led by Dmitry Khorev, a highly experienced developer with over 8 years of experience in producing quality, scalable server and client applications. Dmitry is skilled in creating well-designed, testable, and efficient back-end services using best practices. He has worked on various large Laravel projects, including a crypto exchange, CRM, and high-load IoT system. The course will provide a summary of Dmitry's experience working with Laravel versions 6 to 10.
To successfully participate in this course, you will need a Linux or macOS machine, although Windows users can use VirtualBox to install Ubuntu as an alternative. Docker and Docker-compose should also be installed as they will be used for launching supporting services like databases. If you don't have your environment set up, instructions will be provided in the next lecture.
Previous experience and knowledge required for this course include solid knowledge of Laravel and PHP, understanding of OOP, SOLID, and Dependency Injection principles, experience in writing automated tests with PHPUnit and Laravel, familiarity with Laravel service container (a plus), and knowledge of the Mockery framework (a plus).
In Laravel, the default approach to testing includes UNIT and FEATURE test folders, and it commonly involves high coupling with Database Models. While additional testing types like e2e and integration testing can be introduced in large projects, they are complex and hard to maintain. However, Laravel's approach to unit and feature testing closely aligns with integration and e2e testing, and testing against production-like services boosts confidence in every step. In this course, we will also learn to treat our application as a set of microservices, with different levels of responsibility such as the API layer, scheduler, Horizon task runner, and commands, all connected with shareable Models/DB schema.
This section covers testing paradigms for building future-proof tests in Laravel projects. The first idea is to write tests that will be easily understood six months from now. The second idea is to use tests as documentation for controllers, services, and business logic. Finally, understandable tests can help colleagues onboard faster, with topics covering test suite folder structure, test case naming, test case flow, clear assertions, and use case coverage vs. statement coverage.
This lecture discusses how to organize your test suite folders in Laravel. The recommended approach is to follow the same pattern as your controllers, with a root namespace of Unit, Feature, or Integration, followed by a fully replicated folder structure of a class under tests. The test case file should be named the same as the class with the “Test” suffix. Following this structure makes it easier for others to locate and understand your test files.
This lecture is about best practices for naming test cases. The author recommends selecting a naming pattern and sticking with it, using descriptive names that include inputs and expected outputs, and using keywords like "when" and "then" to separate the different parts of the name. The author also discusses two popular naming patterns: "<ACTION> when <CONDITION> then <RESULT>" and "it <RESULT> when <ACTION><CONDITION>". Finally, the author states that they prefer the original PHPUnit style for naming test cases, but acknowledges that the other patterns are also good choices.
This lecture discusses the benefits of having a structured pattern for all of your tests and suggests splitting the test code into stages. Each stage is responsible for one aspect of the test case - arrange, act, or assert. The lecture provides examples of possible workflows and emphasizes the importance of not overdoing it with unnecessary separation of small test cases.
This lecture discusses the importance of creating clear and focused assertions in test cases to ensure that when something breaks, it is easy to identify and fix the problem quickly. The lecture explains that following the software engineering principle of Single Responsibility can help achieve this goal, and provides an example of how to refactor a test case that tests too many things at once into three separate tests, each focused on a specific level of abstraction. The lecture concludes by encouraging readers to try out the provided code snippets for themselves.
The lecture discusses the different forms of test coverage, including statement coverage, branch coverage, and code coverage. While it is essential to have high coverage in these areas, the author suggests focusing on use case coverage instead. The author demonstrates an example of a "DataService" and its test coverage based on user roles. While the coverage report shows 100% coverage on all metrics, the author points out that one role was not used in the scenarios. The author emphasizes the importance of not solely relying on coverage metrics and instead ensuring that all use cases are covered.
In this section, the focus is on practices that enhance the test suite, making development smoother. While these practices are especially beneficial for larger projects that become more complex over time, the key to maintaining project health is through good software design decisions, comprehensive automated test coverage, and maximizing decoupling.
In this lecture, the emphasis is on the importance of strict checks and strong typing for long-term software projects. Types help reduce coding errors and also act as documentation for classes and methods. An example demonstrates the clarity provided by strong typing. The lecture also highlights PHP-specific options, stressing the need for declaring strict checks, which prevents silent type coercion. Importantly, if a strict file is imported into a non-strict file, type safety is lost. The lecture wraps up by examining the differences between `assertEquals` and `assertSame`, as well as `assertJson` and `assertExactJson` in testing, emphasizing the importance of using the right tools to detect and prevent potential issues in the code.
In this lecture, the discussion revolves around the challenges of using an in-memory SQLite database for Laravel tests and the benefits of using more robust databases like MySQL or Postgres. Although SQLite databases work well for small demos due to their lightweight nature, they aren't typically used in production and can have limitations. Key differences highlighted include SQLite's lax approach to data typing and constraints, which can cause data integrity issues. Through video examples, the lecturer showcases potential problems when testing with SQLite, such as foreign key checks and data type mismatches. The lecture also addresses performance concerns, emphasizing that while bootstrapping might take longer for bigger projects, the actual run-time remains fast. To speed up the process, the lecturer suggests creating periodic schema dumps or running tests in parallel. The takeaway is a recommendation to opt for more robust databases for real-world project testing to ensure long-term benefits.
In this lecture, the issue of date-related flaky tests within Laravel test suites using PHPUnit is explored. The lecture underscores the problems that arise when relying on the `now()` helper to generate fake data points for tests, particularly when tests run for extended periods. Demonstrating with Laravel's DateTest, the lecturer emphasizes the advantages of explicitly setting dates to ensure test consistency. The lecture also delves into the challenges posed by Daylight Savings Time (DST) changes, which can result in discrepancies when adding hours to specific test dates. To counteract these inconsistencies, the lecturer suggests using the CarbonImmutable class to create and set specific test dates. Lastly, the lecture advocates for setting both the application and the database engine to Universal Coordinated Time (UTC) as an additional layer of protection against date-time related discrepancies in tests.
In this lecture, the nuances of testing within Laravel's Redis integration are explored, particularly the disparities observed between testing with the cache store's array driver versus an actual Redis instance. The main issue highlighted is that while the array driver returns data types as expected, Redis often retrieves values, such as floats, as strings. This discrepancy can lead to unexpected behaviors, especially when strict checks are enabled or disabled. The lecture demonstrates, through a practical example, how a simple float retrieval can differ between the two testing methods, potentially causing TypeErrors or unexpected typecasts in PHP. Emphasizing the real-world implications, the lecturer suggests that just as it's advantageous to test with the actual database rather than an in-memory one, it's equally beneficial to test with a real Redis instance if it's going to be used in production.
In application development, the number and complexity of layers can vary based on project factors. Simple applications and microservices often prioritize speed over best practices, while monolithic or complex projects may benefit from additional layers. Typical web application layers include models, repositories, services, controllers, middleware, views, and background tasks, each serving specific purposes in managing data and functionality. In the next lecture, we'll delve into these layers and explore common testing practices for each.
In this lecture, we'll delve into the importance of testing Laravel's Eloquent models. While it might seem that Eloquent models are robust and don't require extensive testing, having a thorough test suite for your models can prove invaluable. We'll explore how tests can provide assurance that your custom configurations and relationships are functioning correctly, ultimately saving you time and preventing potential issues in your Laravel application.
In this lecture, we explore the introduction of a repository layer in Laravel applications—a topic subject to ongoing debate among engineers. We weigh the pros and cons of adding this layer, considering factors like decoupling, testability, and adherence to the Single Responsibility Principle as advantages. However, we also delve into the potential drawbacks, including increased complexity, "leakage" of Eloquent concerns, a learning curve, limitations on Eloquent features, and the possibility of over-engineering for smaller projects. Ultimately, the decision to employ a repository layer should align with your project's unique requirements and team expertise.
This lecture emphasizes the significance of thoroughly testing Laravel's service layer, which plays a central role in managing complex business logic. It advocates a pragmatic approach, focusing on critical aspects of the service layer, such as core business logic, database interactions, data transformation, and error handling. By skipping integration tests with external services and using Laravel's mocking capabilities, developers can maintain a robust test suite while ensuring reliability and efficiency.
This lecture highlights the significance of testing Laravel's controller layer to validate interactions within the application and maintain functionality. It emphasizes testing integration with the service layer, access control, input validation, and authentication mechanisms. By focusing on these aspects, developers can ensure the reliability and security of their controllers while enhancing code readability and maintainability.
This lecture underscores the importance of testing the middleware layer in Laravel, highlighting its role in various technical aspects crucial for application health and performance. It explores middleware use cases such as rate limiting, CORS handling, caching, and debugging. The lecture also emphasizes testing logging, metrics collection, request routing, and authentication/authorization within the middleware layer, ensuring the overall stability and security of the application environment.
This lecture underscores the importance of testing the view layer in Laravel, particularly in API-driven projects, where client-facing response validation is crucial. It emphasizes the validation of API resources, including structure, data counts, and pagination functionality. The focus is on ensuring a reliable and consistent client interface that consistently meets client expectations, even with changes to the application's underlying logic, making it vital for maintaining contracts in API-driven applications.
This lecture highlights the significance of testing the Background Tasks Layer in Laravel, particularly for scalable applications relying on asynchronous operations like events, queues, and scheduled tasks. It outlines what to test within this layer, including cron jobs, regular jobs, events, listeners, data integrity, and asynchronous workflows. Leveraging Laravel's robust testing utilities allows for efficient simulation and validation of these workflows, ensuring a high level of reliability and efficiency in your application's background processes.
Hey there, you! Ready to level up your Laravel skills?
In this course, we're all about making your coding journey smoother and more enjoyable. Imagine having a framework that lets you build code that's not just maintainable but also a pure joy to work with. That's what we're aiming for!
By the end of this journey, you'll become a true Laravel expert. We'll dive deep into strict types, unit, and feature testing – those secret weapons that make your code rock-solid. Plus, we're not stopping at just theory. We're keen on getting hands-on. You'll be crafting and testing real-world asynchronous workflows in Laravel, ensuring that what you build stands the test of time.
But that's not all! We'll tackle complex Laravel projects together. Ever wondered how to test those intricate workflows? We'll break it down step by step, ensuring you gain practical experience.
And here's the kicker: You'll learn how to hit the ground running when onboarding new Laravel projects. Spotting opportunities for improvement will become second nature to you, making you an invaluable asset in any team.
So, what are you waiting for? Let's dive into Laravel and make this year of coding mastery! It's time to embark on this transformative adventure together.