Testing Strategy
Testing Approach
The software testing strategy aims to ensure the delivery of high-quality software by employing a comprehensive testing approach throughout the development lifecycle. This strategy combines various testing types and levels to validate the functionality, performance, and security of the software.
The testing approach for PermaplanT will follow a mix of unit testing, integration testing, and system testing.
- Unit testing will be conducted for individual components and functions to ensure that they are working as expected.
- Integration testing will be conducted for API endpoints and interactions between components to ensure that they are functioning correctly together.
- System testing will be conducted as manual tests and automated e2e tests to ensure the proper functionality of the system as a whole.
The effort necessary to write and maintain the tests should match their impact. Therefore, it is important to identify and use the appropriate types of tests for the current use case. Non-trivial single-component functionality should be covered by unit tests. Non-trivial multi-component functionality should additionally be covered by integration tests. Wherever possible and reasonable system tests should be automated to avoid the variance in scope and granularity that comes with manual testing.
Goals
- Prefer tests that are easy to maintain, e.g., prefer unit tests for detailed logic tests.
- Ensure that the software meets functional requirements and operates as intended.
- Identify and mitigate risks associated with software defects and failures.
- Enhance user experience by maintaining low bug rate and responsiveness.
- Improve overall software quality and reliability.
- Ensure that the 'mr', 'dev', and 'master' environments are tested with full End-to-End (E2E) tests.
- Ensure that the 'www' environment is tested with smoke tests.
Objectives
- Maintain an 80% backend branch coverage.
- Run tests with all environments.
- TBD frontend objectives
- TBD additional objectives
In Scope:
- E2E testing of use cases
- E2E testing of UI for different sizes/devices
- Integration testing of various modules and components
- System tests
- Performance tests
- Security tests
- Regression testing
- User acceptance testing
- Compatibility testing on different platforms, browsers, and devices
Out of Scope:
- Database tests
- Stress tests
Current State of CI/CD Tests
For further information about the environments see doc/ci.md
Production Environment (www)
- Testing: No Tests are currently run on the production environment.
- Since the production environment deploys the master branch, which has already been tested in the CI/CD pipeline, it is not necessary to run additional non-E2E tests.
Master Branch
- Testing: The master branch is currently missing E2E tests.
Test Coverage Across Environments
Test Name | Merge Request | Development | Master | Production |
---|---|---|---|---|
cargo-test | ✔ | ✔ | ✔ | ✘ |
frontend-test | ✔ | ✔ | ✔ | ✘ |
mdbook-test | ✔ | ✔ | ✔ | ✘ |
E2E Test | ✔ | ✔ | ✘ | ✘ |
Goals
The goal is to ensure that all environments pass all tests. Specifically:
-
Production:
- Must pass at least E2E and smoke tests.
- If these tests fail, administrators should be alerted immediately.
-
Master:
- E2E tests must be added and pass consistently.
- If this test fail, administrators should be alerted immediately.
Testing Types and Levels
1. Unit Testing
Unit tests are used to test individual units of code in isolation from the rest of the system. This is important because it allows us to validate that each unit is working as intended, without interference from other parts of the system.
- Unit tests must be created by every developer during the development process, following the Arrange-Act-Assert (AAA) pattern.
Short example:
#![allow(unused)] fn main() { struct Plants; #[cfg(test)] mod tests { use super::*; #[test] fn test_abs_for_a_negative_number() { // Arrange let negative = -5; // Act let answer = abs(negative); // Assert assert_eq!(answer, 5); } } }
Frontend
For the frontend unit tests will be used to test the following areas:
- State management logic: Since the frontend relies heavily on state management, it is important to ensure that the state is being properly managed and updated.
- Functions that handle data manipulation, such as sorting or filtering
- Components that render UI elements
- Correct event handling
- Form validation and submission
Backend
For the backend, unit tests will be used to test the following areas:
- Database queries and operations
- Business logic and data manipulation, e.g. code that performs calculations, manipulates data, or makes decisions based on input
- Authentication and authorization
- Error handling
In the backend unit tests can be found in the src/test
directory.
2. Integration Testing
Integration tests are used to test the integration between different parts of the system. This is important because it allows us to validate that the different parts of the system are working together correctly.
In the application the integration tests will be used to test the following areas:
- Continuous Integration (CI) pipelines must run integration tests for different modules and components.
Frontend
- API calls using a mock API
Backend
- API endpoints
- Database queries
In the backend integration tests can be found in the src/test/
directory.
The whole module is annotated with #[cfg(test)]
and will therefore only be compiled for tests.
3. System Testing
System testing will include end-to-end testing of the application to ensure overall functionality and user experience. This will include testing of all features, navigation, and error handling.
- System test scenarios must be derived from the use cases and the requirements they imply.
- Manual system tests are documented in
doc/tests/manual/protocol.md
. - Automated system tests (e2e tests) can be found in the top-level
e2e
folder. - Both are specified in Gherkin syntax.
- Exploratory testing techniques must be utilized to uncover potential issues and edge cases.
- A subset of system tests (and e2e tests), called smoke tests, must be run on the production environment to ensure that the most important features are working as expected and that the application is healthy.
4. Performance Testing
Load testing will be used to measure system reliability, performance.
5. Security Testing
TBD by @e12022492?
Test Environment and Infrastructure
- Test environments must mirror production environments as closely as possible.
- Virtualization and containerization technologies, such as Docker must be utilized for test environment management.
- Test environments must be version controlled and easily reproducible.
Testing Tools
- E2E: Python Playwright & Pytest + plugins
- Backend: Rust built-in tests by cargo
- Frontend: Vitest
Test Data Management
- Test data must be synthetic.
- Test data must cover a variety of scenarios, including at least valid and invalid cases.
- Equivalence partitioning and boundary value analysis tests should be done when it makes sense.
Test Execution and Reporting
- Test cases must be executed manually or automated, as appropriate for each testing type.
- All automated tests must be executed by CI.
- Integration tests must be executed by the CI pipeline on every push to PR and every merge to master.
- Test metrics, such as test coverage and test execution time, must be tracked in the pipeline.
- System tests and User acceptance tests must be performed before every release.
- Manual tests will be documented under
doc/tests/manual/reports
- An Email is sent whenever master fails, with a small report containing information since last build.
Test Automation
- Unit and Integration tests must be fully automated.
- Security and Performance tests may be manual.
- System tests are automated (if possible) according to the e2e guidelines.
Other Considerations
- Tests should be run before committing via pre-commit hooks
- Tests should be run on different configurations (e.g. production, staging)