-
-
Notifications
You must be signed in to change notification settings - Fork 3
About Testing
Automated testing is essential when developing and maintaining software because it allows catching bugs early and greatly increase the confidence that the application works as intended after doing changes in the code.
The code is tested with test cases that execute a function or action and then compare the actual result with the expected result.
Two main types of functional white-box software testing are unit and integration tests.
Unit tests focus on testing individual units of code in isolation, such as functions, classes,
or modules.
The goal is to ensure that each unit operates as expected and produces the correct
results independently of other parts of the software.
Integration tests focus on testing how different units or modules of code work
together as a cohesive system.
The interaction between components is evaluated
to ensure that they communicate and function correctly as a whole.
Integration tests involve simulating user interactions by creating HTTP requests that traverse all the layers of the backend, communicate with the database and other adapters, and return a response.
That way, the overall behavior of the application can be tested efficiently and easily.
For unit tests, all dependencies surrounding this unit must be replaced by test doubles (mocks, stubs, etc.)
with predefined return values.
This takes time and effort to set up and maintain.
If a dependency changes, for example, a function name, a parameter, or a return value type,
the test double has to be updated in each case.
Unit tests are very precise but not flexible, and they're tightly coupled to the implementation.
This makes sense in some cases, for e.g. when developing a library or when a complex critical
function needs to be tested thoroughly to ensure it works as expected.
But in a lot of cases in real-world web applications, it's not worth the effort to test
every single component individually when they can be tested together with few lines of code
with integration tests.
It can even be counterproductive. If the code is refactored, the unit tests have to be refactored as well, which not only increases the workload but also makes them not a good indicator if the application still works like before.
Ideally, a test should be green before and after refactoring.
This is when writing tests actually makes sense and is worth the extra effort.
The tests make sure that the application works as intended, they're relatively easy to write
and robust to changes in the code, meaning they don't have to be re-written all the time.
The tests are located in the tests
directory with the following structure:
├── Tests
├── Integration # integration tests
├── Unit # unit tests
├── Fixture # database content to be added as preparation in test db for integration tests
├── Provider # data provider to run the same test cases with different data
└── Traits # utility traits (test setup, database connection, helpers)
Documentation about configuration and test setup can be found in Writing Tests.
Most IDEs have built-in support for running tests, but they can also be run from the command line.
The following command shortcut is defined in the
scripts
section
of the composer.json
file:
composer test
To run the tests automatically when pushing, GitHub Actions can be used in combination with tools like Scrutinizer or Codecov to get insights into the code quality.
For more information, see GitHub Actions.
Slim app basics
- Composer
- Web Server config and Bootstrapping
- Dependency Injection
- Configuration
- Routing
- Middleware
- Architecture
- Single Responsibility Principle
- Action
- Domain
- Repository and Query Builder
Features
- Logging
- Validation
- Session and Flash
- Authentication
- Authorization
- Translations
- Mailing
- Console commands
- Database migrations
- Error handling
- Security
- API endpoint
- GitHub Actions
- Scrutinizer
- Coding standards fixer
- PHPStan static code analysis
Testing
Frontend
Other