首页 > 解决方案 > 模拟 Boto3 AWS 调用,客户端是全局的

问题描述

我有一些我正在尝试为其编写单元测试的代码。我在这里查看了其他答案,例如here,尽管我遇到的问题是 Boto3 客户端引用是全局的并且在我正在测试的函数之外。

被测代码的简化版本:

项目结构:

▶ tree .                    
.
├── src
│   └── lib
│       ├── __init__.py
│       └── policy.py
└── tests
    └── test_policy.py

被测代码:

# 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 ""

测试代码:

# 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()

当我运行这个:

▶ 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)

如果我取消注释#client = boto3.client("route53")我得到的行:

▶ 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)

如何通过对 boto3 的修补调用和通过测试来正确设置这一切?

标签: pythonboto3python-unittest.mock

解决方案


推荐阅读