Python自动化中环境变量(env)的作用和使用
📋 环境变量在自动化中的核心作用
作用领域 | 主要用途 | 好处 |
---|---|---|
配置管理 | 存储环境相关的配置参数 | 一套代码多环境运行 |
敏感信息保护 | 存储API密钥、密码等敏感数据 | 不暴露在代码中 |
环境切换 | 区分测试、预生产、生产环境 | 自动化环境切换 |
参数化运行 | 动态调整测试参数和行为 | 灵活控制测试执行 |
🛠️ 常用工具库对比
工具库 | 特点 | 适用场景 | 安装命令 |
---|---|---|---|
python-dotenv |
从.env 文件加载环境变量 |
本地开发和测试 | pip install python-dotenv |
os.environ |
Python内置,直接使用 | 简单场景,系统已有变量 | 内置 |
自定义配置类 | 高度定制化 | 复杂项目结构 | 自定义实现 |
📝 环境变量文件(.env)示例
bash
# 环境配置
ENVIRONMENT=test
BASE_URL=https://api.example.com
API_VERSION=v1
# API认证
API_KEY=sk_test_1234567890
API_SECRET=sec_9876543210
USERNAME=testuser
PASSWORD=testpass123
# UI自动化配置
BROWSER=chrome
HEADLESS=true
TIMEOUT=30
WAIT_TIME=10
# 数据库配置
DB_HOST=localhost
DB_PORT=5432
DB_NAME=test_db
DB_USER=db_user
DB_PASSWORD=db_pass
# 第三方服务
SLACK_WEBHOOK=https://hooks.slack.com/services/xxx
EMAIL_SMTP=smtp.gmail.com
🚀 UI自动化中的使用示例
1. 基础配置管理
python
# config.py
import os
from dotenv import load_dotenv
load_dotenv() # 加载.env文件
class Config:
# 浏览器配置
BROWSER = os.getenv('BROWSER', 'chrome')
HEADLESS = os.getenv('HEADLESS', 'false').lower() == 'true'
TIMEOUT = int(os.getenv('TIMEOUT', '30'))
# 应用配置
BASE_URL = os.getenv('BASE_URL', 'http://localhost:3000')
ADMIN_USER = os.getenv('ADMIN_USER', 'admin')
ADMIN_PASSWORD = os.getenv('ADMIN_PASSWORD', 'admin123')
# 测试配置
SCREENSHOT_ON_FAILURE = os.getenv('SCREENSHOT_ON_FAILURE', 'true').lower() == 'true'
2. Selenium WebDriver配置
python
# driver_setup.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from config import Config
def create_driver():
if Config.BROWSER.lower() == 'chrome':
options = Options()
if Config.HEADLESS:
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome(options=options)
elif Config.BROWSER.lower() == 'firefox':
# Firefox配置
pass
driver.implicitly_wait(Config.TIMEOUT)
return driver
3. 页面对象模型中使用
python
# login_page.py
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from config import Config
class LoginPage:
def __init__(self, driver):
self.driver = driver
self.wait = WebDriverWait(driver, Config.TIMEOUT)
def login(self, username=None, password=None):
username = username or Config.ADMIN_USER
password = password or Config.ADMIN_PASSWORD
self.driver.get(f"{Config.BASE_URL}/login")
self.driver.find_element(By.ID, "username").send_keys(username)
self.driver.find_element(By.ID, "password").send_keys(password)
self.driver.find_element(By.ID, "login-btn").click()
# 等待登录成功
self.wait.until(EC.url_contains("dashboard"))
🌐 API自动化中的使用示例
1. API客户端配置
python
# api_client.py
import requests
import os
from dotenv import load_dotenv
from typing import Dict, Any
load_dotenv()
class APIClient:
def __init__(self):
self.base_url = os.getenv('BASE_URL', 'https://api.example.com')
self.api_key = os.getenv('API_KEY')
self.api_secret = os.getenv('API_SECRET')
self.headers = {
'Authorization': f'Bearer {self.api_key}',
'Content-Type': 'application/json'
}
def get(self, endpoint: str, params: Dict = None) -> Any:
url = f"{self.base_url}/{endpoint}"
response = requests.get(url, headers=self.headers, params=params)
response.raise_for_status()
return response.json()
def post(self, endpoint: str, data: Dict) -> Any:
url = f"{self.base_url}/{endpoint}"
response = requests.post(url, headers=self.headers, json=data)
response.raise_for_status()
return response.json()
2. 测试用例中使用
python
# test_user_api.py
import pytest
from api_client import APIClient
import os
class TestUserAPI:
@pytest.fixture
def api_client(self):
return APIClient()
def test_create_user(self, api_client):
test_email = os.getenv('TEST_EMAIL', 'test@example.com')
user_data = {
"name": "Test User",
"email": test_email,
"password": "testpass123"
}
response = api_client.post('users', user_data)
assert response['email'] == test_email
assert 'id' in response
def test_get_users(self, api_client):
users = api_client.get('users')
assert isinstance(users, list)
3. 多环境测试配置
python
# conftest.py
import pytest
import os
from dotenv import load_dotenv
def pytest_configure(config):
"""根据命令行参数加载不同的环境配置"""
env = config.getoption('--env', default='test')
env_file = f'.env.{env}'
if os.path.exists(env_file):
load_dotenv(env_file)
else:
load_dotenv() # 加载默认的.env文件
def pytest_addoption(parser):
parser.addoption('--env', action='store', default='test',
help='Environment: test, staging, prod')
# 测试用例中可以使用
@pytest.mark.env('staging')
def test_production_ready_features():
# 只在特定环境运行的测试
pass
🔧 高级用法和最佳实践(options)
1. 环境验证和默认值
python
# env_validator.py
import os
from typing import List
def validate_required_env_vars(required_vars: List[str]):
"""验证必需的环境变量是否已设置"""
missing_vars = []
for var in required_vars:
if not os.getenv(var):
missing_vars.append(var)
if missing_vars:
raise EnvironmentError(f"Missing required environment variables: {missing_vars}")
# 在项目启动时验证
REQUIRED_VARS = ['BASE_URL', 'API_KEY', 'DB_HOST']
validate_required_env_vars(REQUIRED_VARS)
2. 类型转换工具函数
python
# env_utils.py
import os
def get_env_bool(key: str, default: bool = False) -> bool:
value = os.getenv(key, '').lower()
if value in ('true', '1', 'yes', 'on'):
return True
elif value in ('false', '0', 'no', 'off'):
return False
return default
def get_env_int(key: str, default: int = 0) -> int:
try:
return int(os.getenv(key, default))
except (ValueError, TypeError):
return default
def get_env_list(key: str, separator: str = ',', default: list = None) -> list:
default = default or []
value = os.getenv(key)
if value:
return [item.strip() for item in value.split(separator)]
return default
3. 安全处理敏感信息
python
# security_utils.py
import os
from cryptography.fernet import Fernet
class EnvEncryptor:
def __init__(self, key=None):
self.key = key or os.getenv('ENCRYPTION_KEY')
if self.key:
self.cipher = Fernet(self.key.encode())
def encrypt_value(self, value: str) -> str:
if self.key:
return self.cipher.encrypt(value.encode()).decode()
return value
def decrypt_value(self, encrypted_value: str) -> str:
if self.key and encrypted_value:
return self.cipher.decrypt(encrypted_value.encode()).decode()
return encrypted_value
# 使用示例
encryptor = EnvEncryptor()
secret_password = encryptor.decrypt_value(os.getenv('ENCRYPTED_PASSWORD'))
📊 Git忽略和安全性
.gitignore 配置
避免将env中的数据传到GIT版本库中 而是在CICD工具中进行配置,例如Jenkins中的凭据管理插件Credentials
python
# 环境变量文件
.env
.env.*
!.env.example
# 敏感信息
*.key
*.pem
*.cert
# 日志和临时文件
logs/
tmp/
环境模板文件 (.env.example)
bash
# 复制此文件为 .env 并填写实际值
BASE_URL=https://api.example.com
API_KEY=your_api_key_here
API_SECRET=your_api_secret_here
BROWSER=chrome
HEADLESS=false
TIMEOUT=30
DB_HOST=localhost
DB_PORT=5432
DB_NAME=your_database
DB_USER=your_username
DB_PASSWORD=your_password
🎯 总结优势
-
安全性:敏感信息不进入代码仓库
-
灵活性:一套代码适应多环境
-
可维护性:配置集中管理,易于修改
-
协作友好:团队协作时各自维护本地配置
-
自动化友好:CI/CD流水线中容易注入环境变量
通过合理使用环境变量,可以构建出更加健壮、安全和灵活的自动化测试框架。