Automatic software tests are an important part of modern software development. They help to detect errors at an early stage, avoid regressions and ensure that applications work reliably in different scenarios. In agile development processes in particular, they enable rapid iterations without the need to repeat manual tests every time.
Depending on the type of test, the technical effort, the speed of test execution and the informative value vary. A well thought-out test strategy is often based on the so-called test pyramid.
The Test Pyramid – Structure for Effective Tests
The test pyramid divides software tests into three levels:
Unit-Tests bilden die Basis und normalerweise werden davon zahlenmäßig am meisten implementiert. Sie tUnit tests form the basis and are usually implemented in the largest numbers. They test small units of code in isolation and are quick to execute. Integration tests are in the middle of the pyramid and check whether several classes or modules work together correctly. At the top are system and end-to-end tests, which test the entire system under realistic conditions. As these tests are more complex, they should be used selectively.
Unit Tests in Practice
Unit tests are the easiest form of automated tests to implement. They are integrated directly into the code repository of a project and written in parallel to the development of new features or bug fixes. In PHP projects with Symfony, we use PHPUnit for this.
A typical example is the testing of a service class. A unit test can test whether a method returns the expected values when it is called with certain inputs. External dependencies such as database accesses or API requests are avoided in unit tests by replacing them with mocks or stubs.
Unit tests are also useful for front-end applications. In Vue.js projects, we use Vitest or Jest to ensure that individual UI components function correctly. For example, we test whether a component generates the correct output when the state changes.
As unit tests can be executed very quickly, they are ideal for continuous integration pipelines in which every code commit is checked automatically.
Integration Tests for the Interaction of Several Classes
While unit tests only look at individual code units, integration tests check the interaction of several classes or modules within the application.
An example from a Symfony project would be checking a service that uses several repository classes to aggregate data from the database. An integration test would test whether the service interacts correctly with these repositories and whether the expected data is returned.
Another example would be a class that combines various internal helper functions to perform a more complex calculation. While a unit test would only test a single method in isolation, an integration test checks whether all classes involved together deliver the expected results.
To implement integration tests, we continue to use PHPUnit in Symfony, but without mocking external dependencies. If a database is involved, a separate test database is used, which is reset to a defined state before each test run.
System Tests and End-to-End Tests
System tests check larger parts of the application or the entire system in a realistic environment. This includes testing APIs in particular.
A common example is the testing of a REST API. Automated requests are sent to various endpoints to test whether the API delivers the expected responses. We perform these tests in Symfony with PHPUnit, using an API client that sends requests and compares the responses.
End-to-end tests (E2E) go one step further and test the entire application from the perspective of a real user. This involves running through a user interaction from the front end to the database. In web applications, we use tools such as Symfony Panther or Cypress for this purpose. These tests simulate how a user navigates through the application, fills out forms and receives results.
For mobile applications, end-to-end testing is more complex, as tests have to be carried out on real devices or emulators. In one of our projects for a hybrid mobile app, we used Appium with Webdriver.io to automate user interactions.
As end-to-end tests are particularly resource-intensive, they are usually only used for critical user flows, such as logging into a system or completing an order process.
Challenges and Best Practices
A good test strategy not only takes into account the coverage of different test levels, but also the maintenance effort. Unit tests are easy to maintain as they are closely linked to the code. Integration tests are more complex as they rely on the cooperation of multiple modules. End-to-end tests often require additional infrastructure, such as test databases or special test accounts.
In our projects, we rely on a mixture of unit and integration tests as well as targeted end-to-end tests for critical user flows. Code coverage tools help us measure the coverage of the tests and ensure that the most important areas of an application are checked.
When tests are written depends on the project type. In agile teams, unit and integration tests are created in parallel with development, often supported by Test-Driven Development (TDD). End-to-end tests are more complex and are often only added after the core functions have been completed.
Sensetence & Software Testing – Our Experience
We have successfully implemented automated tests in numerous projects and optimized various test strategies. Particularly in complex web applications with Symfony or mobile applications, our tests have helped to identify errors at an early stage and increase the stability of the software.
In one of our recent projects for an API-driven web platform, we used a combination of unit tests for business logic and integration tests for the interaction of services. This structure helped to avoid regressions and continuously monitor the quality of the system.
Consulting for Test Automation and Quality Assurance
Would you like to improve your test strategy or optimize test automation in your project? As specialists for software development, we support you in a customized consulting project – from the selection of suitable test methods to the practical implementation in your existing development environment.
Based in Augsburg, we are active throughout Germany – both on-site and remotely. Let’s find out together how we can ensure and optimize the quality of your software in the long term!