如何用Selenium与pytest测试Streamlit应用:元素定位与等待
问题与解决方案
问题概述
我搭建了一个简单的Streamlit应用,想用Selenium和pytest框架测试其UI元素。已完成Chrome浏览器及ChromeDriver的安装、路径配置。待测试脚本app/Home.py代码如下:
import streamlit as st st.set_page_config(page_title="Home") st.title("Welcome to My Streamlit App") st.write("This is the home page of the application.") st.header("Instructions") st.write("Navigate to the sidebar to explore different pages:") st.write("- Home: This page.") st.write("- About: Learn more about the app.") st.subheader("Features") st.write("- Interactive data visualization.") st.write("- Easy navigation between pages.") st.info("Enjoy exploring the app!")
现有pytest测试脚本可测试首页标题,但目前用time.sleep等待应用启动及元素加载,希望改用Selenium内置的隐式/显式等待;同时不清楚如何定位st.header、st.write、st.info对应的页面元素,需解决这两个问题。当前测试脚本:
import subprocess import time import pytest from selenium import webdriver @pytest.fixture(scope="session") def driver(): # Start the Streamlit application as a separate process app_process = subprocess.Popen( ["streamlit", "run", "app/Home.py"] ) # Wait for the Streamlit app to start time.sleep(2) driver = webdriver.Chrome() yield driver driver.quit() # Stop the Streamlit application process after the test app_process.terminate() app_process.wait() def test_home_title(driver): driver.get("http://localhost:8501") # How to find the streamlit element and then wait for them to being ready? time.sleep(1) assert driver.title == "Home"
解决方案
1. 替换time.sleep为Selenium等待机制
隐式等待
在初始化Driver后设置全局隐式等待,让Driver在查找元素时自动等待指定时长,无需重复编写等待逻辑:
driver = webdriver.Chrome() driver.implicitly_wait(10) # 最多等待10秒 yield driver
显式等待(推荐)
针对特定元素或条件做精准等待,比隐式等待更灵活,比如等待Streamlit应用启动完成:
先导入相关模块:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC
然后在fixture中替换原time.sleep(2):
# 先打开页面,再等待标题加载完成 driver.get("http://localhost:8501") WebDriverWait(driver, 15).until(EC.title_is("Home"))
2. Streamlit元素定位方法
Streamlit生成的HTML元素带有特定class属性,可结合文本内容或class进行定位:
- st.title:对应
<h1>标签,class为stTitle,定位示例:title_element = WebDriverWait(driver, 10).until( EC.presence_of_element_located(("xpath", "//h1[text()='Welcome to My Streamlit App']")) ) - st.header:对应
<h2>标签,class为stHeader,定位示例:header_element = WebDriverWait(driver, 10).until( EC.presence_of_element_located(("xpath", "//h2[text()='Instructions']")) ) - st.write:内容通常在class为
stMarkdown或stText的<div>中,定位示例:write_element = WebDriverWait(driver, 10).until( EC.presence_of_element_located(("xpath", "//div[contains(text(),'This is the home page of the application.')]")) ) - st.info:对应class为
stAlert的<div>,定位示例:info_element = WebDriverWait(driver, 10).until( EC.presence_of_element_located(("xpath", "//div[@class='stAlert' and contains(text(),'Enjoy exploring the app!')]")) )
修改后的完整测试脚本
import subprocess import pytest from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC @pytest.fixture(scope="session") def driver(): # 启动Streamlit应用 app_process = subprocess.Popen(["streamlit", "run", "app/Home.py"]) # 初始化Driver并设置隐式等待 driver = webdriver.Chrome() driver.implicitly_wait(10) # 显式等待应用启动完成 driver.get("http://localhost:8501") WebDriverWait(driver, 15).until(EC.title_is("Home")) yield driver # 清理资源 driver.quit() app_process.terminate() app_process.wait() def test_home_page_elements(driver): # 验证页面标题 assert driver.title == "Home" # 验证st.title元素 title = WebDriverWait(driver, 10).until( EC.presence_of_element_located(("xpath", "//h1[text()='Welcome to My Streamlit App']")) ) assert title.is_displayed() # 验证st.header元素 header = WebDriverWait(driver, 10).until( EC.presence_of_element_located(("xpath", "//h2[text()='Instructions']")) ) assert header.is_displayed() # 验证st.write文本 write_text = WebDriverWait(driver, 10).until( EC.presence_of_element_located(("xpath", "//div[contains(text(),'This is the home page of the application.')]")) ) assert write_text.is_displayed() # 验证st.info元素 info_box = WebDriverWait(driver, 10).until( EC.presence_of_element_located(("xpath", "//div[@class='stAlert' and contains(text(),'Enjoy exploring the app!')]")) ) assert info_box.is_displayed()
内容的提问来源于stack exchange,提问作者Péter Szilvási
相关产品推荐
相关产品推荐

