我必须在 python 中模拟全局变量,但变量值来自另一个函数。当我导入文件时,这个函数正在运行,但我想要那里的模拟值。
secrets.py
import traceback
import logging
import boto3
import os
import json
logger = logging.getLogger()
logger.setLevel(logging.INFO)
secret_name = os.environ['SECRETS_NAME']
region_name = os.environ['AWS_REGION']
config_secret = dict()
def init_config_secret():
session = boto3.session.Session()
client = session.client(
service_name='secretsmanager',
region_name=region_name
)
try:
config_secret_value = client.get_secret_value(SecretId=secret_name)
if 'SecretString' in config_secret_value:
global config_secret
config_secret = json.loads(config_secret_value['SecretString'])
return config_secret
except Exception as e:
logger.error('Error while retrieving secrets')
traceback.print_exc()
def get_config_secret():
if not bool(config_secret):
return init_config_secret()
else:
return config_secret
if __name__ == '__main__':
get_config_secret()
request_auth.py
import requests
from secrets import get_config_secret
from datetime import datetime, timedelta
config = get_config_secret()
print(f'config: {config}')
token = None
def verifySSL() :
return True
def get_api_root_url():
return config["url"]
def build_request_header(access_token, content_type):
return {
"authorization" : access_token,
"Content-Type" : content_type
}
def get_access_token():
global token
if token is None:
acquire_token()
elif token["expiry"] < datetime.now():
acquire_token()
return token["authToken"]
def acquire_token():
auth_payload = {
"grant_type" : "client_credentials",
"client_id" : config["id"]
}
response = requests.post(config["url"], data = auth_payload, verify = verifySSL())
# print(response.json())
global token
token= dict()
token["authToken"] = response.json()["access_token"]
token["expiry"] = datetime.now() + timedelta(minutes = 10)
test_request_auth.py
import json, sys
import unittest, os
from unittest.mock import patch, Mock
from unittest import mock
from request_auth import *
class TestRequestAuth(unittest.TestCase):
@patch("request_auth.config", {"test": "test"})
@patch("request_auth.get_config_secret")
def test_get_api_root_url(self, mock_get_config_secret):
mock_get_config_secret.return_value = {"url": "test"}
self.assertEqual(get_api_root_url(), "https://test.test.com/")
我尝试了这种方式,但不工作不确定需要做什么。 有人可以帮忙吗?
在测试中遇到的问题是,
config
变量是在导入
request_auth
模块时被初始化的,该操作发生在的测试函数运行之前。这意味着的补丁无法生效,因为
config
变量已经被赋值了。
为了解决这个问题,可以将
config
变量的初始化延迟到需要使用它的时候。以下是如何修改的代码来实现这一点:
request_auth.py:
import requests
from secrets import get_config_secret
from datetime import datetime, timedelta
# 不要在这里直接初始化 config
# config = get_config_secret()
# ... 其他代码 ...
def get_api_root_url():
# 在需要使用 config 时再调用 get_config_secret()
config = get_config_secret()
return config.get("url", "")
# ... 其他代码 ...
test_request_auth.py:
import unittest
from unittest.mock import patch
from request_auth import get_api_root_url, get_config_secret # 导入 get_config_secret
class TestRequestAuth(unittest.TestCase):
@patch("request_auth.get_config_secret")
def test_get_api_root_url(self, mock_get_config_secret):
mock_get_config_secret.return_value = {"url": "https://test.test.com/"}
self.assertEqual(get_api_root_url(), "https://test.test.com/")
在这个修改后的代码中:
-
我们从
request_auth.py
中移除了config = get_config_secret()
这一行,这样就不会在模块导入时初始化config
。 -
我们在
get_api_root_url
函数内部调用get_config_secret()
,以确保在需要使用config
变量时才获取它的值。 -
在测试代码中,我们直接 mock
request_auth.get_config_secret
函数,这样就可以控制get_api_root_url
函数内部获取到的config
值。
通过这种方式,可以成功地模拟
get_config_secret
函数的返回值,从而在测试中控制
config
变量的值。