From 45e56c385e39d6ad1de22d38a3353dfec174f4d2 Mon Sep 17 00:00:00 2001 From: spwoodcock Date: Mon, 22 Jan 2024 15:32:53 +0000 Subject: [PATCH] docs: more detail on types of tests --- docs/dev-guide/testing.md | 85 +++++++++++++++++----------------- docs/images/test_pyramid.webp | Bin 0 -> 15600 bytes 2 files changed, 42 insertions(+), 43 deletions(-) create mode 100644 docs/images/test_pyramid.webp diff --git a/docs/dev-guide/testing.md b/docs/dev-guide/testing.md index e7da565..05f2bd5 100644 --- a/docs/dev-guide/testing.md +++ b/docs/dev-guide/testing.md @@ -2,31 +2,51 @@ ## Types of Testing +### Code Tests + +![test-pyramid](./images/test_pyramid.webp) + - **Unit Testing:** - - Focuses on testing individual units or components of a software in isolation. - - Validates that each unit of code performs as designed. + - Testing specific isolated functions or classes in your code. + - Inputs are pre-defined and outputs are mocked to verify the code + works as intended. + - Unit tests can be written for the backend (e.g. Pytest) and frontend + (e.g. Vitest). - **Integration Testing:** - Verifies that different units or modules work together as expected. - Identifies issues in interactions between integrated components. - -- **Functional Testing:** - - - Validates that the software functions according to specified requirements. - - Ensures that the system behaves as expected from the end-users' perspective. - -- **Regression Testing:** - - - Ensures that new code changes don't negatively impact existing functionalities. - - Detects unintended side effects caused by modifications. - -- **Acceptance Testing:** - - - Validates that the entire system meets the specified requirements - and is accepted by stakeholders. - - Can include user acceptance testing (UAT) and business acceptance testing. + - For example and endpoint on a web API can be tested for expected + output, which may run various different functions throughout the code. + - Typically backend tests, but can also be written to group together + multiple frontend unit tests (e.g. testing a component state). + +- **User Interface (UI) Testing:** + + - Checking for changes to the user interface functionality can be + automated. + - As of 2024, a great tool to do this is + [Playwright](https://github.com/microsoft/playwright). + - The idea is to navigate to various pages and see if the output is as + expected. + - For example, a screenshot of a page can be taken on a page load, then + compared against a page load in a future test. This will determine if + any unexpected visual regression has occured. + - Page elements can be navigated and interacted with using [various + properties](https://playwright.dev/docs/locators), such as element + names, ids, labels, to lower level CSS and XPath if required. + +- **End-to-End (E2E) Testing:** + + - Similar to integration tests, except the entire expected user + workflow is tested. + - For example, if you expect a user to create a user account --> + create a project --> perform some processing, then these steps will + be tested in order (as if the user was using the software). + +### Other Tests - **Performance Testing:** @@ -39,28 +59,11 @@ - Identifies vulnerabilities and weaknesses in the software's security features. - Ensures that sensitive data is protected and the system is resistant to attacks. -- **Usability Testing:** - - - Assesses the software's user interface, user experience, and overall - user-friendliness. - - Focuses on how easily users can interact with and navigate through the application. - -- **Compatibility Testing:** - - - Ensures that the software functions correctly across different - devices, browsers, and operating systems. - - Verifies compatibility with various configurations. - - **Smoke Testing:** - - A subset of tests to verify basic functionality and ensure the - stability of a new build. - - Quick checks performed before more comprehensive testing. - -- **Exploratory Testing:** - - - Informal testing approach where testers explore the application to find defects. - - Emphasizes discovery and learning during the testing process. + - A test to pretty much see if your application starts up. + - If a smoke test fails, then you application failed to initialise. + - Particularly useful to test if a container runs as expected. - **White Box Testing:** @@ -73,17 +76,13 @@ - Tests the software's functionality without knowing its internal code or logic. - Focuses on inputs and outputs, treating the software as a "black box". -- **Ad-hoc Testing:** - - - Informal and unplanned testing approach. - - Testers explore the application without predefined test cases. - - **Alpha Testing:** - Conducted by a select group of users before the software's public release. - Focuses on identifying major issues before wider deployment. - **Beta Testing:** + - Conducted by a larger group of users in a real-world environment. - Gathers feedback from end-users to improve the software before the final release. diff --git a/docs/images/test_pyramid.webp b/docs/images/test_pyramid.webp new file mode 100644 index 0000000000000000000000000000000000000000..46ef7e6dad7f420a9f8762c72a1ebaf62ef01fb0 GIT binary patch literal 15600 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 z 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 B8S?-D literal 0 HcmV?d00001