Files
novalon-website/e2e-tests/tests/test_performance.py
T
张翔 f14002559e feat(e2e-tests): 添加端到端测试框架及测试用例
refactor(components): 调整头部和页脚布局样式
style(hero-section): 更新徽章动画效果

docs: 添加测试框架README文档
test: 实现首页、导航和联系表单的测试用例
ci: 添加CI测试脚本和配置
2026-02-02 19:36:33 +08:00

322 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
性能测试模块
测试网站性能指标
"""
import pytest
import time
from typing import Dict, Any
from datetime import datetime
from pages.home_page import HomePage
from pages.contact_page import ContactPage
from config.settings import get_settings
class TestPerformance:
"""性能测试类"""
@pytest.mark.performance
@pytest.mark.smoke
def test_home_page_load_time(self, home_page: HomePage):
"""测试首页加载时间"""
home_page.navigate()
start_time = time.time()
home_page.wait_for_load()
end_time = time.time()
load_time = (end_time - start_time) * 1000 # 毫秒
# 阈值:5秒
assert load_time < 5000, f"首页加载时间 {load_time:.2f}ms 超过5秒阈值"
@pytest.mark.performance
@pytest.mark.smoke
def test_contact_page_load_time(self, contact_page: ContactPage):
"""测试联系页面加载时间"""
contact_page.navigate()
start_time = time.time()
contact_page.wait_for_load()
end_time = time.time()
load_time = (end_time - start_time) * 1000
# 阈值:5秒
assert load_time < 5000, f"联系页面加载时间 {load_time:.2f}ms 超过5秒阈值"
@pytest.mark.performance
def test_dom_content_loaded_time(self, home_page: HomePage):
"""测试DOM内容加载时间"""
home_page.navigate()
performance_data = home_page.execute_js("""
() => {
const timing = performance.timing;
return {
domContentLoaded: timing.domContentLoadedEventEnd - timing.navigationStart,
domInteractive: timing.domInteractive - timing.domLoading
};
}
""")
dom_loaded = performance_data.get("domContentLoaded", 0)
assert dom_loaded < 3000, f"DOM内容加载时间 {dom_loaded}ms 超过3秒阈值"
@pytest.mark.performance
def test_first_paint_time(self, home_page: HomePage):
"""测试首次绘制时间"""
home_page.navigate()
first_paint = home_page.execute_js("""
() => {
const entries = performance.getEntriesByType('paint');
const firstPaint = entries.find(e => e.name === 'first-paint');
return firstPaint ? firstPaint.startTime : 0;
}
""")
if first_paint:
assert first_paint < 2000, f"首次绘制时间 {first_paint:.2f}ms 超过2秒阈值"
@pytest.mark.performance
def test_first_contentful_paint(self, home_page: HomePage):
"""测试首次内容绘制(FCP"""
home_page.navigate()
fcp = home_page.execute_js("""
() => {
const navigation = performance.getEntriesByType('navigation')[0];
return navigation ? navigation.firstContentfulPaint : 0;
}
""")
if fcp:
# 阈值:1.5秒
assert fcp < 1500, f"首次内容绘制时间 {fcp:.2f}ms 超过1.5秒阈值"
@pytest.mark.performance
def test_largest_contentful_paint(self, home_page: HomePage):
"""测试最大内容绘制(LCP"""
home_page.navigate()
lcp = home_page.execute_js("""
() => {
try {
const navigation = performance.getEntriesByType('navigation')[0];
return navigation ? navigation.largestContentfulPaint : 0;
} catch (e) {
return 0;
}
}
""")
if lcp:
# 阈值:2.5秒
assert lcp < 2500, f"最大内容绘制时间 {lcp:.2f}ms 超过2.5秒阈值"
@pytest.mark.performance
def test_time_to_interactive(self, home_page: HomePage):
"""测试可交互时间(TTI"""
home_page.navigate()
tti = home_page.execute_js("""
() => {
try {
const navigation = performance.getEntriesByType('navigation')[0];
return navigation ? navigation.interactive : 0;
} catch (e) {
return 0;
}
}
""")
if tti:
# 阈值:3秒
assert tti < 3000, f"可交互时间 {tti:.2f}ms 超过3秒阈值"
@pytest.mark.performance
def test_page_load_performance_metrics(self, home_page: HomePage):
"""测试页面加载性能指标"""
home_page.navigate()
performance = home_page.verify_page_performance()
# 验证关键指标
if performance.get("pageLoadTime"):
assert performance["pageLoadTime"] < 5000
if performance.get("domContentLoaded"):
assert performance["domContentLoaded"] < 3000
@pytest.mark.performance
def test_network_timing(self, home_page: HomePage):
"""测试网络时序"""
home_page.navigate()
timing = home_page.execute_js("""
() => {
const timing = performance.timing;
return {
dnsLookup: timing.domainLookupEnd - timing.domainLookupStart,
tcpConnection: timing.connectEnd - timing.connectStart,
serverResponse: timing.responseEnd - timing.requestStart,
domProcessing: timing.domLoading - timing.responseEnd
};
}
""")
# DNS查询时间
assert timing.get("dnsLookup", 0) < 500, \
f"DNS查询时间 {timing.get('dnsLookup')}ms 超过500ms阈值"
# TCP连接时间
assert timing.get("tcpConnection", 0) < 500, \
f"TCP连接时间 {timing.get('tcpConnection')}ms 超过500ms阈值"
# 服务器响应时间
assert timing.get("serverResponse", 0) < 1000, \
f"服务器响应时间 {timing.get('serverResponse')}ms 超过1秒阈值"
@pytest.mark.performance
def test_resource_timing(self, home_page: HomePage):
"""测试资源加载时序"""
home_page.navigate()
resources = home_page.execute_js("""
() => {
const entries = performance.getEntriesByType('resource');
const scripts = entries.filter(e => e.initiatorType === 'script');
const styles = entries.filter(e => e.initiatorType === 'css');
return {
totalResources: entries.length,
scriptCount: scripts.length,
styleCount: styles.length,
totalDuration: entries.reduce((sum, e) => sum + e.duration, 0)
};
}
""")
assert resources.get("totalResources", 0) > 0, "未检测到资源加载"
home_page.logger.info(
f"资源统计: 共{resources.get('totalResources')}个资源,"
f"脚本{resources.get('scriptCount')}个,"
f"样式{resources.get('styleCount')}"
)
@pytest.mark.performance
def test_form_submission_time(self, contact_page: ContactPage, test_data_generator):
"""测试表单提交时间"""
contact_page.navigate()
data = test_data_generator.generate_contact_form_data(use_valid=True)
start_time = time.time()
contact_page.fill_contact_form(data)
contact_page.submit_form()
try:
contact_page.verify_form_submission_success()
except Exception:
pass
end_time = time.time()
duration = (end_time - start_time) * 1000
# 阈值:5秒
assert duration < 5000, f"表单提交耗时 {duration:.2f}ms 超过5秒阈值"
@pytest.mark.performance
def test_scroll_performance(self, home_page: HomePage):
"""测试滚动性能"""
home_page.navigate()
# 执行多次滚动
scroll_times = []
for i in range(5):
start_time = time.time()
home_page.scroll_to_bottom()
home_page.scroll_to_top()
end_time = time.time()
scroll_times.append((end_time - start_time) * 1000)
avg_scroll_time = sum(scroll_times) / len(scroll_times)
# 平均滚动时间应该在1秒内
assert avg_scroll_time < 1000, f"平均滚动时间 {avg_scroll_time:.2f}ms 超过1秒阈值"
@pytest.mark.performance
def test_element_visibility_performance(self, home_page: HomePage):
"""测试元素可见性检查性能"""
home_page.navigate()
elements = [
"header",
"#home",
"#about",
"#services",
"#products",
"#news",
"#contact",
"footer"
]
check_times = []
for element in elements:
start_time = time.time()
try:
home_page._is_visible(element)
except Exception:
pass
end_time = time.time()
check_times.append((end_time - start_time) * 1000)
avg_check_time = sum(check_times) / len(check_times)
# 单个元素检查时间应该在500ms内
assert avg_check_time < 500, f"平均元素检查时间 {avg_check_time:.2f}ms 超过500ms阈值"
@pytest.mark.performance
def test_navigation_performance(self, home_page: HomePage, contact_page: ContactPage):
"""测试导航性能"""
# 测量导航到联系页面的时间
start_time = time.time()
contact_page.navigate()
contact_page.wait_for_load()
end_time = time.time()
nav_time = (end_time - start_time) * 1000
# 阈值:3秒
assert nav_time < 3000, f"导航时间 {nav_time:.2f}ms 超过3秒阈值"
@pytest.mark.performance
@pytest.mark.responsive
def test_performance_across_viewports(self, home_page: HomePage):
"""测试不同视口下的性能"""
viewports = [
(375, 667, "移动端"),
(768, 1024, "平板端"),
(1920, 1080, "桌面端")
]
results = []
for width, height, name in viewports:
home_page.page.set_viewport_size({"width": width, "height": height})
start_time = time.time()
home_page.navigate()
home_page.wait_for_load()
end_time = time.time()
load_time = (end_time - start_time) * 1000
results.append((name, load_time))
home_page.logger.info(f"{name} ({width}x{height}): {load_time:.2f}ms")
# 验证所有视口加载时间在阈值内
for name, load_time in results:
assert load_time < 5000, f"{name}加载时间 {load_time:.2f}ms 超过5秒阈值"