面试题目
1、当你使用requests库进行接口测试时,如何处理重定向的请求?
主要影响参数为allow_redirects。
默认情况下allow_redirects=True,即自动处理重定向请求。
import requests
# 发起请求,允许重定向
response = requests.get('http://example.com', allow_redirects=True)
# 处理响应
print(response.status_code)
print(response.url)
print(response.history) # 历史重定向信息
print(response.text)
如果手动设置allow_redirects=False,则需手动处理重定向请求。
重定向地址从首次请求返回响应的headers中取location字段。
import requests
# 发起请求,但不允许重定向
response = requests.get('http://example.com', allow_redirects=False)
# 检查是否有重定向
if response.status_code == 302:
# 如果有重定向,获取重定向的地址
redirect_url = response.headers['Location']
# 再次发起请求到重定向的地址
redirected_response = requests.get(redirect_url)
# 处理重定向后的响应
print(redirected_response.text)
else:
# 处理正常的响应
print(response.text)
2、 在PyTest中,如何使用fixture实现接口登录的前置操作?
核心思路是定义一个fixure,在fixure中完成接口登录操作获取token,从而让后续的测试脚本可以显式或隐式地通过该token完成业务接口调用操作。
以先login再profile的业务流程为例。
base_api定义
import os
import allure
import requests
from utils.log_utils import logger
from utils.path_utils import get_root_path
from utils.token_utils import TokenUtils
class BaseApi:
def __init__(self, account, password=None):
self.base_url = 'https://evercraft.co'
# 先从文件中获取token,如果获取失败则重新登录
with allure.step('获取token'):
try:
self.token = TokenUtils.get_token_from_file(account)
except:
self.token = ''
if self.token == '':
login_r = self.login({'account': account, 'password': password})
token = login_r.json()['data']['access_token']
token_path = os.sep.join([get_root_path(), 'data', 'token', f'token_{account}'])
with open(token_path, 'w+') as f:
f.write(token)
def send_request(self, **kwargs):
r = requests.request(**kwargs)
return r
def login(self, data):
url = self.base_url + '/example/v2/user/sign_in'
kwargs = {
'method': 'POST',
'url': url,
'json': data
}
r = self.send_request(**kwargs)
logger.info(r.text)
return r
User类定义
from apis.base_api_xyz import BaseApi
from utils.log_utils import logger
class User(BaseApi):
def get_profile(self):
url = self.base_url + '/example/v2/user/profile'
kwargs = {
'method': 'GET',
'url': url,
'headers': {'Authorization': f'Bearer {self.token}'}
}
r = self.send_request(**kwargs)
logger.info(r.text)
return r
fixture定义
import pytest
from apis.evercraft.user import User
@pytest.fixture(scope='session')
def login():
yield User('ErasedLau@163.com', '123456')
测试脚本
class TestGetProfile:
# 调用login fixture
def test_get_profile(self, login):
user = login
r = user.get_profile()
assert r.status_code == 200
r_json = r.json()
assert r_json['code'] == 0
assert r_json['data']['name'] == 'UserName'
3、描述一个你之前设计的接口自动化框架的结构,包括目录结构、关键模块等。
- 【接口合集】对应框架目录中的apis目录,主要是对各种业务接口对象的抽象,类似于UI自动化测试中的PO但不完全等同于PO。以“项目”对象为例,我们可以封装一个Project类,然后将add、delete、modify、get方法完善,分别对应到“项目”的增删改查接口。
- 【用例目录】对应框架目录中的testcase目录,主要就是归档各个模块的测试用例以及前后置脚本(fixture、setup、teardown)
- 【工具目录】对应框架目录中的utils目录,主要包含db、logger、json_schema、webhook等工具
- 【配置目录】对应框架目录中的configs目录,主要包含像env、db之类的配置信息(yaml文件)
- 【数据目录】对应框架目录中的data目录,主要存储测试用例所需数据(yaml文件)
- 【日志目录】对应框架目录中的logs目录,主要存储测试用例执行过程中产生的日志
- 【报告目录】对应框架目录中的reports目录,存储测试用例执行完毕后产生的allure测试报告
- 【测试入口】使用makefile封装简化执行测试的入口
4、如何在PyTest中实现接口返回结果的断言?
- 断言响应状态码
assert r.status_code == 200
- 断言响应文本(通常是json文本)
assert r.json()['data']['name'] == 'user name'
- 借助json_schema断言json结构体
class JsonSchemaUtils:
@classmethod
def validate_json_schema(cls, obj, **kwargs):
"""通过jsonschema校验json"""
if 'file' in kwargs:
with open(kwargs['file']) as f:
schema = json.load(f)
else: # 'schema' in kwargs
schema = kwargs['schema']
try:
jsonschema.validate(obj, schema)
return True
except Exception as e:
print(f'jsonschema验证失败,捕获异常:\n{e}')
return False
5、在接口自动化测试中,如何处理接口之间的依赖关系?
- 【内部接口】如果待测试接口依赖于系统内部其他接口,则直接调用该接口返回对应依赖数据进行测试,如调用登录接口获取token用于后续业务接口测试。
- 【外部依赖】如果待测试接口依赖于第三方系统接口,通常采用mock的方式模拟返回需要的响应数据
6、请描述如何使用Python的requests库进行文件上传操作。
(待学习整理…)
7、在设计接口自动化框架时,如何确保测试数据的隔离性,避免测试之间的数据干扰?
测试数据之间的数据干扰,我经历过的有2种:
- 【同一用例的测试数据干扰】对于单条测试用例而言,如果测试数据是固定的,那么用例执行完成后如果没有进行后置清理,就会导致下一次执行测试失败。对于这种情况,每次测试时在测试数据后面加上时间戳,并在测试执行前后进行环境清理可以解决问题。
- 【不同用例的测试数据干扰】对于多条测试用例而言,如果使用相同的测试数据,也有可能影响到其他用例。对于这种情况,针对不同的用例设置单独的测试数据可以解决问题。
8、解释HTTP状态码 201 和 204 的区别及应用场景。
(待学习整理…)
9、描述如何使用requests库处理HTTPS请求中的SSL证书验证。
(答案可能不够完善)
主要通过requests请求中的verify参数来控制。
- 当verify=False时,禁用SSL证书验证,可用于临时规避测试环境无HTTPS的测试情况。
- 当verify传入具体证书地址时可开启SSL证书验证。
import requests
# 指定SSL证书的路径
cert_path = '/path/to/certificate.pem'
# 发送HTTPS请求并验证SSL证书
response = requests.get('https://example.com', verify=cert_path)
# 处理响应
print(response.text)
10、在PyTest中如何实现参数化测试,提供一个实例。
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.support import expected_conditions
class TestParametrize:
def setup_method(self):
service = Service(executable_path=ChromeDriverManager().install())
self.driver = webdriver.Chrome(service=service)
self.driver.implicitly_wait(10)
self.driver.get("https://example.com/sign/in")
password_login_entry_el = self.driver.find_element(By.XPATH, '//span[text()="密码登录"]')
WebDriverWait(self.driver, 5).until(expected_conditions.element_to_be_clickable(password_login_entry_el))
password_login_entry_el.click()
WebDriverWait(self.driver, 5).until(
expected_conditions.text_to_be_present_in_element((By.TAG_NAME, 'h2'), '密码登录')
)
def teardown_method(self):
self.driver.quit()
@pytest.mark.parametrize('account,password,target', [
('13145899433', '123456', '选择进入身份'), ('13145899433', '1234567', '密码有误')
])
def test_parametrize(self, account, password, target):
account_input_el = self.driver.find_element(By.CSS_SELECTOR, 'input[placeholder="请输入手机号码或邮箱"]')
password_input_el = self.driver.find_element(By.CSS_SELECTOR, 'input[placeholder="请输入密码"]')
account_input_el.send_keys(account)
password_input_el.send_keys(password)
login_button_el = self.driver.find_element(By.XPATH, '//button[text()="登录"]')
login_button_el.click()
target_el = self.driver.find_element(By.XPATH, f'//*[contains(text(), "{target}")]')
assert target_el.is_displayed()
11、描述在接口测试中使用Mock和Stub的优势和应用场景。
(待学习整理…)
12、如何处理大文件的上传和下载,并在接口测试中的应用。
(待学习整理…)
13、描述如何将接口自动化测试集成到CI/CD流程中。
(待学习整理…)
14、请描述HTTP协议的工作流程,包括TCP三次握手和四次挥手。
(待学习整理…)