Afonso de Gouveia

<- Development

Unit Testing

When writing code using TDD, you always start with the tests. These are the most important pointers about unit testing.

Only Test Business Logic

Tests should be self-contained and not access anything unless it's through the business logic being tested. That means no direct access to databases, web resources or different modules.

Don't Depend on Implementation Details

Test code defines the behaviour your actual code is supposed to have and should work regardless of the data structure or method calls used inside the methods you're calling. You may be tempted to adjust a test case to make your code pass; stop and consider whether the change belongs in the test. Ideally, you don't change your test once you start writing the code being tested.

Integration Testing

If you develop with SOLID principles in mind, dependencies between modules will be handled through interfaces and dependency injection. A Unit Test mocks a dependency, while an Integration Test uses an actual implementation. If module A depends on module B and you need to test how they integrate, pass a real instance of B to A.

This is needed when functionality depends on multiple components to make business sense and you want to assure that basic actions can be performed with the codebase as it stands. It reduces the odds that a unit-level change breaks interdependencies.

E2E (End-to-End) Testing

A full solution is meant to be used by a user. Some functionalities or use cases will be critical to the business, and you want to be certain code changes do not break them. Automate the user flow through a real deployment and use automation tools to validate that everything looks and behaves as expected. This replaces repetitive manual testing and lets quality-assurance people focus on user experience and defining test cases to automate.

Assurances

Testing provides assurances. Once you feel confident in your coverage, changes can be made much faster because mistakes during refactoring or bug correction are very likely to be caught.

The testing pyramid

The types of tests above are ordered by quantity. The base of the pyramid should be unit tests, providing the most coverage and confidence, followed by integration tests, E2E tests and potentially manual testing. This is a requirement for agile development; otherwise, test coverage can become slow, unmaintainable and unrepresentative of the most relevant test cases.

If you don't follow these rules, you may end up with an unmaintainable project because its complexity can no longer be managed or because maintenance costs are too high.