I have some code that I am attempting to write unit tests for. I have looked at other answers here e.g. here although I have the problem that the Boto3 client reference is global and outside of the function I am testing.
A simplified version of the code under test:
Project structure:
▶ tree .
.
├── src
│ └── lib
│ ├── __init__.py
│ └── policy.py
└── tests
└── test_policy.py
Code under test:
# src/lib/policy.py
import boto3
client = boto3.client("route53")
def get_policy_id(policy_name: str) -> str:
response = client.list_traffic_policies()
for policy in response["TrafficPolicySummaries"]:
if policy["Name"] == policy_name:
return policy["Id"]
return ""
Test code:
# tests/test_policy.py
import sys
sys.path.insert(0, "./src/lib") # FIXME. Ignore.
import unittest
import boto3
from policy import get_policy_id
from unittest.mock import patch
class TestPolicy(unittest.TestCase):
@patch("boto3.client.list_traffic_policies")
@patch("boto3.client")
def test_get_policy_id(self, client, list_traffic_policies):
list_traffic_policies.return_value = {
"TrafficPolicySummaries": [
{
"Id": "e89c8276-483b-4b1b-a737-9016e0374066",
"Name": "*.example.com",
"Type": "A",
"LatestVersion": 1,
"TrafficPolicyCount": 1
}
],
"IsTruncated": False,
"MaxItems": "100"
}
#client = boto3.client("route53")
response = get_policy_id("*.example.com")
client.assert_called_with("route53")
list_traffic_policies.assert_called()
self.assertEqual(response, "e89c8276-483b-4b1b-a737-9016e0374066")
def main():
unittest.main()
if __name__ == "__main__":
main()
When I run this:
▶ python3 tests/test_policy.py
F
======================================================================
FAIL: test_get_policy_id (__main__.TestPolicy)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/alexharvey/.pyenv/versions/3.6.9/lib/python3.6/unittest/mock.py", line 1183, in patched
return func(*args, **keywargs)
File "tests/test_policy.py", line 37, in test_get_policy_id
client.assert_called_with("route53")
File "/Users/alexharvey/.pyenv/versions/3.6.9/lib/python3.6/unittest/mock.py", line 805, in assert_called_with
raise AssertionError('Expected call: %s\nNot called' % (expected,))
AssertionError: Expected call: client('route53')
Not called
----------------------------------------------------------------------
Ran 1 test in 1.263s
FAILED (failures=1)
If I uncomment the line #client = boto3.client("route53")
I get:
▶ python3 tests/test_policy.py
F
======================================================================
FAIL: test_get_policy_id (__main__.TestPolicy)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/alexharvey/.pyenv/versions/3.6.9/lib/python3.6/unittest/mock.py", line 1183, in patched
return func(*args, **keywargs)
File "tests/test_policy.py", line 37, in test_get_policy_id
client.assert_called_with("route53")
File "/Users/alexharvey/.pyenv/versions/3.6.9/lib/python3.6/unittest/mock.py", line 805, in assert_called_with
raise AssertionError('Expected call: %s\nNot called' % (expected,))
AssertionError: Expected call: mock('route53')
Not called
----------------------------------------------------------------------
Ran 1 test in 1.291s
FAILED (failures=1)
How do I set this all up correctly with a patched call to boto3 and passing tests?