forked from nhs-england-tools/playwright-python-blueprint
-
Notifications
You must be signed in to change notification settings - Fork 2
Feature/bcss 21355 subject assertion util #125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
adrianoaru-nhs
merged 4 commits into
main
from
feature/BCSS-21355-subject-assertion-util
Aug 28, 2025
Merged
Changes from 3 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| # Utility Guide: Subject Assertion Utility | ||
|
|
||
| This guide explains the purpose and usage of the `subject_assertion` utility found in [`utils/subject_assertion.py`](../../utils/subject_assertion.py). | ||
| It is designed to assert that a subject with a given NHS number matches specified criteria in the database, and provides detailed logging when criteria do not match. | ||
|
|
||
| --- | ||
|
|
||
| ## Table of Contents | ||
|
|
||
| - [Utility Guide: Subject Assertion Utility](#utility-guide-subject-assertion-utility) | ||
| - [Table of Contents](#table-of-contents) | ||
| - [Overview](#overview) | ||
| - [Required Arguments](#required-arguments) | ||
| - [How It Works](#how-it-works) | ||
| - [Example Usage](#example-usage) | ||
| - [Behaviour Details](#behaviour-details) | ||
| - [Best Practices](#best-practices) | ||
| - [Reference](#reference) | ||
|
|
||
| --- | ||
|
|
||
| ## Overview | ||
|
|
||
| The `subject_assertion` function is used to verify that a subject in the database matches a set of criteria. | ||
| If the subject does not match all criteria, the function will iteratively loop through each criteria (except NHS number), logging any criteria that caused the assertion to fail. | ||
|
|
||
| --- | ||
|
|
||
| ## Required Arguments | ||
|
|
||
| - `nhs_number` (`str`): The NHS number of the subject to check. | ||
| - `criteria` (`dict`): A dictionary of criteria to match against the subject's attributes. | ||
|
|
||
| --- | ||
|
|
||
| ## How It Works | ||
|
|
||
| 1. The function first checks if the subject with the given NHS number matches all provided criteria. | ||
| 2. If not, it removes checks one criterion at a time and retries the assertion. | ||
Andyg79 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 3. This process continues until all criteria have been checked. | ||
| 4. If a match is found only after removing criteria, the failed criteria are logged. | ||
| 5. The function returns `True` only if all criteria match on the first attempt; otherwise, it returns `False`. | ||
|
|
||
| --- | ||
|
|
||
| ## Example Usage | ||
|
|
||
| Below are examples of how to use `subject_assertion` in your tests: | ||
|
|
||
| ```python | ||
| import pytest | ||
| from utils.subject_assertion import subject_assertion | ||
|
|
||
| pytestmark = [pytest.mark.utils_local] | ||
|
|
||
| def test_subject_assertion_true(): | ||
| nhs_number = "9233639266" | ||
| criteria = {"screening status": "Inactive", "subject age": "> 28"} | ||
Andyg79 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| assert subject_assertion(nhs_number, criteria) is True | ||
| ``` | ||
|
|
||
| See `tests_utils/test_subject_assertion_util.py` for more examples. | ||
|
|
||
| --- | ||
|
|
||
| ## Behaviour Details | ||
|
|
||
| - The function always keeps the NHS number criterion. | ||
| - If a match is found only after removing criteria, the failed criteria are logged in the format: | ||
| - Failed criteria: Key: 'key1', Value: 'value1' | ||
| - The function will only return `True` if all criteria match on the first attempt. | ||
|
|
||
| --- | ||
|
|
||
| ## Best Practices | ||
|
|
||
| - Use this utility to validate subject data in database-driven tests. | ||
| - Review logs for failed criteria to diagnose why assertions did not pass. | ||
| - Always provide the NHS number as part of your criteria. | ||
|
|
||
| --- | ||
|
|
||
| ## Reference | ||
|
|
||
| - [`utils/subject_assertion.py`](../../utils/subject_assertion.py) | ||
| - [`tests_utils/test_subject_assertion_util.py`](../../tests_utils/test_subject_assertion_util.py) | ||
| - [SubjectSelectionQueryBuilder Utility Guide](SubjectSelectionQueryBuilder.md) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| import pytest | ||
| from utils.subject_assertion import subject_assertion | ||
|
|
||
| pytestmark = [pytest.mark.utils_local] | ||
|
|
||
| nhs_number = "9233639266" | ||
|
|
||
|
|
||
| def test_subject_assertion_true(): | ||
| criteria = {"screening status": "Inactive", "subject age": "> 28"} | ||
| assert subject_assertion(nhs_number, criteria) is True | ||
|
|
||
|
|
||
| def test_subject_assertion_false(): | ||
| criteria = {"screening status": "Call", "subject age": "< 28"} | ||
| assert subject_assertion(nhs_number, criteria) is False | ||
|
|
||
|
|
||
| def test_subject_assertion_false_with_some_true(): | ||
| criteria = { | ||
| "screening status": "Inactive", | ||
| "subject age": "> 28", | ||
| "latest episode type": "FOBT", | ||
| "latest episode status": "Open", | ||
| "latest episode has referral date": "Past", | ||
| "latest episode has diagnosis date": "No", | ||
| "latest episode diagnosis date reason": "NULL", | ||
| } | ||
| assert subject_assertion(nhs_number, criteria) is False |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| from utils.oracle.subject_selection_query_builder import SubjectSelectionQueryBuilder | ||
| from utils.oracle.oracle import OracleDB | ||
| from classes.subject import Subject | ||
| from classes.user import User | ||
| import logging | ||
|
|
||
|
|
||
| def subject_assertion(nhs_number: str, criteria: dict) -> bool: | ||
| """ | ||
| Asserts that a subject with the given NHS number exists and matches the provided criteria. | ||
| Args: | ||
| nhs_number (str): The NHS number of the subject to find. | ||
| criteria (dict): A dictionary of criteria to match against the subject's attributes. | ||
| Returns: | ||
| bool: True if the subject matches the provided criteria, False if it does not. | ||
| """ | ||
| nhs_number_string = "nhs number" | ||
| subject_nhs_number_string = "subject_nhs_number" | ||
| nhs_no_criteria = {nhs_number_string: nhs_number} | ||
| subject = Subject() | ||
| user = User() | ||
| builder = SubjectSelectionQueryBuilder() | ||
|
|
||
| query, bind_vars = builder.build_subject_selection_query( | ||
| criteria=nhs_no_criteria, | ||
| user=user, | ||
| subject=subject, | ||
| subjects_to_retrieve=1, | ||
| ) | ||
|
|
||
| subject_df = OracleDB().execute_query(query, bind_vars) | ||
| subject = Subject.from_dataframe_row(subject_df.iloc[0]) | ||
|
|
||
| criteria[nhs_number_string] = nhs_number | ||
|
|
||
| # Check all criteria together first | ||
| query, bind_vars = builder.build_subject_selection_query( | ||
| criteria=criteria, | ||
| user=user, | ||
| subject=subject, | ||
| subjects_to_retrieve=1, | ||
| ) | ||
| df = OracleDB().execute_query(query, bind_vars) | ||
| if nhs_number in df[subject_nhs_number_string].values: | ||
| return True | ||
|
|
||
| # Check each criterion independently | ||
| failed_criteria = [] | ||
| criteria_keys = [key for key in criteria if key != nhs_number_string] | ||
| for key in criteria_keys: | ||
| single_criteria = {nhs_number_string: nhs_number, key: criteria[key]} | ||
| query, bind_vars = builder.build_subject_selection_query( | ||
| criteria=single_criteria, | ||
| user=user, | ||
| subject=subject, | ||
| subjects_to_retrieve=1, | ||
| ) | ||
| df = OracleDB().execute_query(query, bind_vars) | ||
| if ( | ||
| subject_nhs_number_string not in df.columns | ||
| or nhs_number not in df[subject_nhs_number_string].values | ||
| ): | ||
| failed_criteria.append((key, criteria[key])) | ||
|
|
||
| if failed_criteria: | ||
| log_message = "Subject Assertion Failed\nFailed criteria:\n" + "\n".join( | ||
| [f"{key}, {value}" for key, value in failed_criteria] | ||
| ) | ||
| logging.error(log_message) | ||
| else: | ||
| logging.error( | ||
| "Subject Assertion Failed: Criteria combination is invalid or conflicting." | ||
| ) | ||
|
|
||
| return False |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.