Skip to content
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

Fix/tests using called_once_with #2363

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

sastels
Copy link
Collaborator

@sastels sastels commented Nov 18, 2024

Summary | Résumé

There's no such thing as mock.called_once_with() - pytest thinks this is a new mocked function and so lines such as

assert mock.called_once_with("sadness")

will always pass. 😢

So there are a few tests that have been passing despite sometimes actually not testing things correctly.

There is a mock.assert_called_once_with() that we can use instead though. This PR mostly changes to those.

Discovered because Python 3.12 doesn't allow this craziness.

Test instructions | Instructions pour tester la modification

none

Release Instructions | Instructions pour le déploiement

None.

Reviewer checklist | Liste de vérification du réviseur

  • This PR does not break existing functionality.
  • This PR does not violate GCNotify's privacy policies.
  • This PR does not raise new security concerns. Refer to our GC Notify Risk Register document on our Google drive.
  • This PR does not significantly alter performance.
  • Additional required documentation resulting of these changes is covered (such as the README, setup instructions, a related ADR or the technical documentation).

⚠ If boxes cannot be checked off before merging the PR, they should be moved to the "Release Instructions" section with appropriate steps required to verify before release. For example, changes to celery code may require tests on staging to verify that performance has not been affected.

db_value,
)
else:
mocked_set.assert_not_called()
Copy link
Collaborator Author

@sastels sastels Nov 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're mocking the code that involves the set (fetch_todays_email_count()) so the set isn't actually called. That's ok since this code is tested above, so it's cleaner to mock it out in this test (we just can't test the set)

db_value,
)
else:
mocked_set.assert_not_called()
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as above.

)
else:
mocked_set.assert_not_called()
with set_config(client.application, "REDIS_ENABLED", True):
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't set REDIS_ENABLED then increment_todays_email_count() immediately returns None, and it turns out that REDIS_ENABLED is false in CI by default.

@sastels sastels marked this pull request as ready for review November 18, 2024 20:19
@@ -161,7 +161,7 @@ def test_process_sns_results_does_not_process_other_providers(sample_template, m
)

process_sns_results(response=sns_success_callback(reference="ref1")) is None
assert mock_logger.called_once_with("")
assert mock_logger.call_count == 1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of using mock_logger.call_count == 1, it would be more precise to use mock_logger.assert_called_once() to ensure that the logger was called exactly once.

@@ -104,14 +104,14 @@ def test_acknowledge_happy_path(self, mocker):
acknowledge_sms_normal_mock = mocker.patch("app.sms_normal.acknowledge", return_value=True)
acknowledge_sms_priority_mock = mocker.patch("app.sms_bulk.acknowledge", return_value=False)
acknowledge_receipt(SMS_TYPE, NORMAL, receipt)
assert acknowledge_sms_normal_mock.called_once_with(receipt)
acknowledge_sms_normal_mock.assert_called_once_with(receipt)
assert acknowledge_sms_priority_mock.not_called()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method assert_not_called() should be used instead of assert acknowledge_sms_priority_mock.not_called() to properly assert that the mock was not called.

)
else:
mocked_set.assert_not_called()

@pytest.mark.parametrize("redis_value, db_value, increment_by", [(None, 5, 5), ("3", 5, 3)])
def test_increment_todays_requested_email_count(self, mocker, sample_service, redis_value, db_value, increment_by):
def test_increment_todays_requested_email_count(self, client, mocker, sample_service, redis_value, db_value, increment_by):
cache_key = email_daily_count_cache_key(sample_service.id)
mocker.patch("app.redis_store.get", lambda x: redis_value if x == cache_key else None)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mocked_set variable is being used in the test but it is not defined. You should add back the line mocked_set = mocker.patch("app.redis_store.set") to ensure the test works correctly.

@@ -21,29 +21,22 @@ def test_fetch_todays_requested_sms_count(client, mocker, sample_service, redis_

assert actual_result == expected_result
if redis_value is None:
assert mocked_set.called_once_with(
mocked_set.assert_called_once_with(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The indentation of the ex=7200 argument should be aligned with the previous arguments for better readability.

)
else:
mocked_set.assert_not_called()


@pytest.mark.parametrize("redis_value,db_value,increment_by", [(None, 5, 5), ("3", 5, 3)])
def test_increment_todays_requested_sms_count(mocker, sample_service, redis_value, db_value, increment_by):
def test_increment_todays_requested_sms_count(mocker, client, sample_service, redis_value, db_value, increment_by):
cache_key = sms_daily_count_cache_key(sample_service.id)
mocker.patch("app.redis_store.get", lambda x: redis_value if x == cache_key else None)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mocked_set variable is removed but still referenced in the test. Either remove the references to mocked_set or reintroduce the variable.

Copy link
Collaborator

@jzbahrai jzbahrai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanksfor finding and fixing this!

@sastels
Copy link
Collaborator Author

sastels commented Nov 18, 2024

oh dear I found more, we also have use lines like assert mock.not_called() instead of mock.assert_not_called() :/ Let me add these....

Copy link
Member

@andrewleith andrewleith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks for finding these and cleaning them up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants