Automation testing of business logic in complex applications has a long history, starting from the first scripts for validating validators to modern microservice tests. As the architectures have become more complex (monolith, SOA, micro- and macroservices), a problem has arisen: changes at one level of architecture often break tests at other levels.
The problem lies in the need to write tests that are resilient to the reorganization of interactions between the layers of the application: changing contracts, data structures, and business processes. Often, tests are tied to implementation details, making them "fragile" and difficult to maintain.
The solution is to build tests according to the "black box" principle, focusing on input/output data, using layers of abstraction to access system entities (e.g., Service Layer and Domain Layer in architecture). It is essential to separate business logic from infrastructural details and use mocks/stubs for external dependencies to ensure isolation and stability of tests.
Key features:
What is the difference between testing business logic through the UI layer and testing through the API/Domain Layer?
UI tests are often less resilient to changes since even minor changes in the interface lead to test failures. Tests through the API or Domain Layer depend less on the front end and more successfully isolate the verification of business rules.
Do we need to mock all dependencies of business logic for testing them?
No! It is not necessary to mock what can be implemented in the testing environment (e.g., lightweight memory instead of a database). Mocks are needed for complex, expensive, or external dependencies. Complete mocking can lead to "fake" tests that do not reflect real scenarios.
Is testing only positive scenarios sufficient for business logic?
No! It is crucial to cover all corner cases and negative scenarios; otherwise, critical errors will go unnoticed, leading to vulnerabilities in the main business process.
In a project, business logic was tested only through UI Selenium tests, directly interacting with buttons and forms. Each frontend refactor led to mass test failures.
Pros:
Cons:
In the project, a layer of API and unit tests was implemented. The UI covered only critical paths, while all other validation occurred through the service layer with mocking of expensive services.
Pros:
Cons: