刚开始接触Web自动化测试时,我最先学会的就是send_keys()这个神奇的方法。它就像你的虚拟手指,可以帮你在网页上输入任何内容。记得第一次用它在百度搜索框里自动输入"Hello World"时,那种成就感至今难忘。
send_keys()是Selenium WebDriver提供的一个核心方法,主要作用就是模拟键盘输入。无论是文本框、密码框还是富文本编辑器,只要是能接收键盘输入的元素,它都能搞定。在实际项目中,我经常用它来测试表单提交、搜索功能和各种输入验证场景。
先来看个最简单的例子:
python复制from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://www.baidu.com")
search_box = driver.find_element_by_name("wd")
search_box.send_keys("自动化测试")
search_box.submit()
这段代码做了三件事:打开浏览器访问百度、找到搜索框、输入"自动化测试"并提交。虽然简单,但已经包含了自动化测试的基本流程。新手常犯的错误是没等页面加载完就急着操作元素,我建议加上显式等待:
python复制from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.NAME, "wd"))
)
element.send_keys("这次不会出错了")
表单测试是自动化测试中最常见的场景之一。去年我负责一个电商项目,光登录表单就有十几种验证逻辑。send_keys()帮了大忙,特别是测试各种边界值时。
测试登录表单时,我通常会准备以下几类测试用例:
python复制# 邮箱格式验证测试
email_field = driver.find_element_by_id("email")
email_field.send_keys("invalid.email") # 故意缺少@符号
submit_button.click()
# 验证错误提示是否出现
error_message = driver.find_element_by_class_name("error-message")
assert "请输入有效的邮箱地址" in error_message.text
现代网页很多都是动态加载的,我遇到过最坑的是一个注册表单,选择不同国家会动态改变手机号输入框的格式。处理这种场景的关键是等待元素准备好:
python复制# 选择国家后等待手机输入框出现
country_select = driver.find_element_by_id("country")
country_select.select_by_value("US")
phone_input = WebDriverWait(driver, 5).until(
EC.presence_of_element_located((By.ID, "phone"))
)
phone_input.send_keys("1234567890") # 美国格式号码
掌握了基础用法后,我发现send_keys()还能玩出很多花样。比如模拟快捷键操作、处理富文本编辑器等。
测试一个在线文档编辑器时,我需要验证各种快捷键是否正常工作:
python复制from selenium.webdriver.common.keys import Keys
text_area = driver.find_element_by_id("editor")
text_area.send_keys("测试文本")
# 全选文本
text_area.send_keys(Keys.CONTROL + "a")
# 加粗
text_area.send_keys(Keys.CONTROL + "b")
常用的特殊键还有:
虽然严格来说不是send_keys()的功能,但文件上传也是输入测试的重要部分:
python复制# 注意:必须是<input type="file">元素
file_input = driver.find_element_by_css_selector("input[type='file']")
file_input.send_keys("/path/to/test/file.jpg")
做了这么多项目,我踩过的send_keys()相关的坑也不少,这里分享几个典型案例。
有一次测试一个"高级搜索"表单,部分输入框默认是隐藏的,需要点击按钮才会显示。直接对隐藏元素用send_keys()会报错,必须先让它显示:
python复制# 先点击展开按钮
expand_button = driver.find_element_by_id("advanced-toggle")
expand_button.click()
# 等待动画完成
time.sleep(0.5) # 简单处理,实际项目建议用EC.visibility_of
# 现在可以操作了
advanced_field = driver.find_element_by_id("advanced-field")
advanced_field.send_keys("测试内容")
在测试一个自动完成搜索框时,发现输入太快会导致建议列表不更新。解决方案是模拟人工输入速度:
python复制def slow_send_keys(element, text, delay=0.1):
for char in text:
element.send_keys(char)
time.sleep(delay)
search_box = driver.find_element_by_id("search")
slow_send_keys(search_box, "慢速输入测试")
当测试用例越来越多时,send_keys()的执行效率就变得很重要了。我总结了几条优化经验:
python复制# 性能对比:常规方式 vs JS注入
element = driver.find_element_by_id("large-text")
# 常规方式(较慢)
element.send_keys("这是一段很长的测试文本..."*100)
# JS方式(较快)
driver.execute_script("arguments[0].value = arguments[1]",
element, "这是一段很长的测试文本..."*100)
不同浏览器对send_keys()的处理有时会有差异。我在Chrome上运行良好的脚本,到了Firefox上可能就会出问题。
最常见的两个问题:
解决方案是:
python复制# 跨浏览器兼容的输入示例
def robust_send_keys(element, text):
element.clear()
for char in text:
try:
element.send_keys(char)
except Exception as e:
# 记录错误但继续执行
print(f"输入字符{char}时出错:{str(e)}")
time.sleep(0.05) # 增加短暂延迟
# 验证输入是否完整
assert element.get_attribute("value") == text
现在很多项目都需要同时测试桌面端和移动端。移动端自动化测试中send_keys()的使用有些特殊注意事项。
移动设备上的输入通常会触发虚拟键盘,可能影响页面布局。我的经验是:
python复制# Appium中的输入示例
element = driver.find_element_by_id("mobile-input")
element.click() # 确保获取焦点
element.send_keys("移动端测试")
# 隐藏键盘(Appium特有)
driver.hide_keyboard()
在实际项目中,send_keys()通常不会单独使用,而是集成到测试框架中。我常用的模式是封装一个通用的输入方法:
python复制class BasePage:
def __init__(self, driver):
self.driver = driver
def safe_send_keys(self, locator, text, timeout=10):
try:
element = WebDriverWait(self.driver, timeout).until(
EC.element_to_be_clickable(locator)
)
element.clear()
element.send_keys(text)
return True
except Exception as e:
print(f"输入失败:{str(e)}")
return False
# 使用示例
login_page = LoginPage(driver)
login_page.safe_send_keys((By.ID, "username"), "testuser")
这种封装的好处是:
单纯的输入测试有时不够,我经常需要结合视觉验证来确保输入后的页面显示正确。比如测试富文本编辑器时:
python复制# 输入文本
editor = driver.find_element_by_id("rich-editor")
editor.send_keys("测试富文本")
# 截图比较
expected_screenshot = "expected.png"
actual_screenshot = "actual.png"
driver.save_screenshot(actual_screenshot)
# 使用专门的视觉对比库进行比较
compare_result = compare_images(expected_screenshot, actual_screenshot)
assert compare_result < 0.1 # 相似度阈值
在CI/CD流水线中运行send_keys()测试时,有几个关键点需要注意:
python复制# 无头Chrome配置示例
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument("--headless")
chrome_options.add_argument("--disable-gpu")
driver = webdriver.Chrome(options=chrome_options)
send_keys()也可以用于安全测试,比如:
python复制# SQL注入测试示例
username_field = driver.find_element_by_id("username")
username_field.send_keys("admin' OR '1'='1") # 经典SQL注入
login_button.click()
# 验证是否正确处理了非法输入
error_message = driver.find_element_by_class_name("error")
assert "非法字符" in error_message.text
为了让测试报告更有价值,我通常会在关键输入操作前后添加日志和截图:
python复制def logged_send_keys(element, text, step_name):
print(f"开始步骤:{step_name}")
print(f"输入内容:{text}")
# 操作前截图
driver.save_screenshot(f"before_{step_name}.png")
element.send_keys(text)
# 操作后截图
driver.save_screenshot(f"after_{step_name}.png")
print("步骤完成")
最近遇到一个特别棘手的场景:测试一个实时协同编辑的文档系统。多个用户同时编辑时,send_keys()的时序控制就变得非常重要。我的解决方案是:
python复制def coordinated_send_keys(element, text, cooldown=1):
for char in text:
element.send_keys(char)
time.sleep(cooldown) # 降低输入速度
# 检查是否有冲突提示
try:
conflict_msg = driver.find_element_by_class_name("conflict-alert")
if conflict_msg.is_displayed():
print("检测到编辑冲突,等待解决...")
time.sleep(3)
except:
pass
在性能测试中,我经常需要监控输入操作的响应时间:
python复制import time
from prometheus_client import Summary
INPUT_TIME = Summary('input_operation_seconds', 'Time spent on input operations')
@INPUT_TIME.time()
def timed_send_keys(element, text):
start_time = time.time()
element.send_keys(text)
duration = time.time() - start_time
if duration > 1: # 超过1秒的输入操作需要关注
print(f"警告:输入操作耗时{duration:.2f}秒")
return duration
无障碍测试中,send_keys()可以帮助验证键盘导航是否正常:
python复制# 测试纯键盘操作流程
driver.get("https://example.com")
# 模拟Tab键导航
body = driver.find_element_by_tag_name("body")
body.send_keys(Keys.TAB) # 导航到第一个可聚焦元素
# 验证当前焦点元素
focused = driver.switch_to.active_element
assert focused.get_attribute("id") == "main-search"
国际化项目需要测试各种语言的输入,包括中文、日文、阿拉伯语等:
python复制# 多语言输入测试
test_cases = [
("中文", "简体中文测试"),
("日本語", "日本語テスト"),
("العربية", "اختبار اللغة العربية")
]
for lang, text in test_cases:
print(f"测试{lang}输入")
input_field = driver.find_element_by_id("multi-lang-input")
input_field.clear()
input_field.send_keys(text)
# 验证输入是否正确保存
saved_text = input_field.get_attribute("value")
assert saved_text == text
我经常用send_keys()配合Faker库生成各种测试数据:
python复制from faker import Faker
fake = Faker()
# 生成测试数据
def generate_test_data():
return {
"name": fake.name(),
"email": fake.email(),
"address": fake.address(),
"phone": fake.phone_number()
}
# 填充表单
data = generate_test_data()
driver.find_element_by_id("name").send_keys(data["name"])
driver.find_element_by_id("email").send_keys(data["email"])
# 其他字段...
健壮的测试脚本需要有完善的异常处理机制。这是我的标准做法:
python复制def robust_input(locator, text, max_retries=3):
for attempt in range(max_retries):
try:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located(locator)
)
element.clear()
element.send_keys(text)
return True
except Exception as e:
print(f"尝试 {attempt + 1} 失败: {str(e)}")
if attempt == max_retries - 1:
raise
time.sleep(1)
随着项目迭代,页面元素经常变化。为了减少维护成本,我建议:
python复制# Page Object示例
class LoginPage:
def __init__(self, driver):
self.driver = driver
self.username_field = (By.ID, "username")
self.password_field = (By.ID, "password")
def login(self, username, password):
self.driver.find_element(*self.username_field).send_keys(username)
self.driver.find_element(*self.password_field).send_keys(password)
self.driver.find_element(By.ID, "submit").click()
虽然send_keys()是个老方法,但在可见的未来仍会继续发挥重要作用。不过随着技术的发展,一些新趋势值得关注:
我在实际项目中已经开始尝试结合计算机视觉来增强传统定位方式,效果不错但稳定性还需要提升。