PythonSelenium教程展示了如何使用Python中的Selenium框架自动化Web应用程序测试。
硒
Selenium是用于测试Web应用程序的可移植框架。Selenium可在Windows、Linux和macOS上运行。
SeleniumWebDriver是一组开源API,用于自动测试Web应用程序。有适用于Chrome、Firefox、Opera、MicrosoftEdge等浏览器的特定驱动程序。这些驱动程序需要下载并放在PATH中。SeleniumWebDriver支持不同的编程语言,包括Python、C#和Java。
Selenium可以在完整模式或无头模式下运行。在无头模式下,浏览器没有启动。
Selenium驱动程序
我们需要从https://selenium-python.readthedocs.io/installation.html#drivers下载我们使用的浏览器的驱动程序。驱动程序必须放在PATH中,例如/usr/bin/
,/usr/local/bin/
或当前工作目录。
PythonSelenium安装
使用以下命令安装selenium模块:
$ pip install selenium
这将安装selenium
模块。
PythonSeleniumFirefox示例
对于Firefox浏览器,我们从https://github.com/mozilla/geckodriver/releases下载驱动程序(geckodriver.exe
forWindows)。
#!/usr/bin/python from selenium.webdriver import Firefox from selenium.webdriver.firefox.options import Options opts = Options() opts.headless = True driver = Firefox(options=opts) try: driver.get('http://webcode.me') print(browser.title) assert 'My html page' == driver.title finally: driver.quit()
在示例中,我们使用Firefox的驱动程序测试网页标题。
opts = Options() opts.headless = True driver = Firefox(options=opts)
我们以无头模式创建驱动程序。浏览器将不会启动。
try: driver.get('http://webcode.me') print(driver.title) assert 'My html page' == driver.title
我们向webcode.me
页面发出获取请求并获取其标题。我们对标题的内容进行断言。
finally: driver.quit()
最后,我们退出了驱动程序。
PythonSeleniumChrome示例
对于Chrome浏览器,我们从https://sites.google.com/a/chromium.org/chromedriver/downloads下载驱动程序(chromedriver.exe
forWindows)。
#!/usr/bin/python from selenium.webdriver import Chrome from selenium.webdriver.chrome.options import Options opts = Options() opts.headless = True driver = Chrome(options=opts, executable_path='chromedriver.exe') try: driver.get('http://webcode.me') assert 'My html page!' == driver.title finally: driver.quit()
在这个例子中,我们使用Chrome浏览器。
driver = Chrome(options=opts, executable_path='chromedriver.exe')
我们创建了一个Chrome驱动程序的实例。executable_path
指向可执行文件;如果未指定,则假定可执行文件位于PATH中。
assert 'My html page!' == driver.title
我们添加了额外的感叹号,因此测试将失败。
> py chrome_get_title.py DevTools listening on ws://127.0.0.1:61178/devtools/browser/14d2fd68-eb2a-415a-9bf0-53a0f7b388d6 My html page Traceback (most recent call last): File "chrome_get_title.py", line 19, in <module> assert 'My html page!' == driver.title AssertionError
PythonSelenium页面源码
page_source
属性获取当前页面的来源。
#!/usr/bin/python from selenium.webdriver import Firefox from selenium.webdriver.firefox.options import Options opts = Options() opts.headless = True driver = Firefox(options=opts) try: driver.get('http://webcode.me') title = driver.title content = driver.page_source print(content) assert title == 'My html page' assert 'Today is a beautiful day' in content finally: driver.quit()
在示例中,我们测试页面源中的标题和特定文本。
PythonSelenium查找元素
我们可以使用find_elements_by_tag_name
、find_element_by_id
或find_elements_by_class_name
等方法来定位HTML元素并获取其内容。
#!/usr/bin/python from selenium.webdriver import Firefox from selenium.webdriver.firefox.options import Options opts = Options() opts.headless = True driver = Firefox(options=opts) try: driver.get('http://webcode.me') els = driver.find_elements_by_tag_name("p") for el in els: print(el.text) finally: driver.close()
在示例中,我们获取并打印了webcode.me
首页上的两段文字。
els = driver.find_elements_by_tag_name("p")
我们使用find_elements_by_tag_name
方法找到p
标签。
for el in els: print(el.text)
我们遍历元素列表并使用text
属性打印它们的内容。
> py get_paragraphs.py Today is a beautiful day. We go swimming and fishing. Hello there. How are you?
PythonSelenium警告框
在下面的示例中,我们展示了如何测试JavaScript警告框。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Test page</title> </head> <body> <button id="mybtn" onclick="alert('Hello there!')"> Click </button> </body> </html>
我们有一个带按钮的HTML页面。当我们点击按钮时,会出现一个警告框。
#!/usr/bin/python import time from pathlib import Path from selenium.common.exceptions import TimeoutException from selenium.webdriver import Firefox from selenium.webdriver.support import expected_conditions as ec from selenium.webdriver.support.wait import WebDriverWait myfile = Path.cwd() / "index.html" driver = Firefox() try: driver.get(f'file://{myfile}') button = driver.find_element_by_id("mybtn") button.click() time.sleep(2) try: WebDriverWait(driver, 3).until(ec.alert_is_present(), 'Timed out waiting for confirmation popup to appear') alert = driver.switch_to.alert assert alert.text == 'Hello there!' alert.accept() print("alert accepted") except TimeoutException: print("no alert") time.sleep(5) finally: driver.quit()
在示例中,我们单击按钮元素并检查警告框的文本。
try: driver.get(f'file://{myfile}') button = driver.find_element_by_id("mybtn") button.click() time.sleep(2)
我们在磁盘上加载一个文件,找到按钮元素并点击它。在这个例子中,浏览器出现了;因此,我们休眠2秒,以便我们可以看到发生了什么。
WebDriverWait(driver, 3).until(ec.alert_is_present(), 'Timed out waiting for confirmation popup to appear')
使用WebDriverWait
,我们等待3秒以等待警报出现。如果该框没有出现,我们会提供一条错误消息。
alert = driver.switch_to.alert assert alert.text == 'Hello there!'
我们检查警告框的文本。
PythonSelenium单元测试示例
unittest
是一个Python单元测试框架。它是JUnit的Python语言版本,JUnit是Java编程语言的原始单元测试框架。unittest
支持测试自动化、共享测试的设置和关闭代码、将测试聚合到集合中以及测试与报告框架的独立性。
unittest
提供了一个基类,TestCase
,可用于创建新的测试用例。setUp
是一个钩子方法,用于在运行前设置测试夹具,tearDown
是一个钩子方法,用于在测试后解构测试夹具。
testfixture表示执行一个或多个测试所需的准备工作,以及任何相关的清理操作。这可能涉及,例如,创建临时或代理数据库、目录或启动服务器进程。测试用例是指单独测试的测试函数。函数的名称必须以test
开头。使用各种断言方法执行检查,例如assertIn
、assertTrue
或assertEqual。
测试套件是测试用例、测试套件或两者的集合。它用于聚合应该一起执行的测试。测试运行器
是一个组件,用于编排测试的执行并向用户提供结果。运行程序可以使用图形界面、文本界面或返回一个特殊值来指示执行测试的结果。unittest
、pytest
和nose
是Python测试运行器的示例。
#!/usr/bin/python import unittest from selenium import webdriver from selenium.webdriver.firefox.options import Options class WebCode(unittest.TestCase): def setUp(self): opts = Options() opts.headless = True self.driver = webdriver.Firefox(options=opts) def test_title(self): self.driver.get("http://webcode.me") self.assertIn("My html page", self.driver.title) def test_paragraphs(self): self.driver.get("http://webcode.me") els = self.driver.find_elements_by_tag_name("p") self.assertIn('Today is a beautiful day', els[0].text) self.assertIn('Hello there', els[1].text) def tearDown(self): self.driver.close() if __name__ == "__main__": unittest.main()
我们有一个测试文件,我们在其中检查webcode.me
主页的标题和段落。
def setUp(self): opts = Options() opts.headless = True self.driver = webdriver.Firefox(options=opts)
在setUp
方法中,我们设置了Firefox驱动程序。
def test_title(self): self.driver.get("http://webcode.me") self.assertIn("My html page", self.driver.title)
test_title
方法是单个测试用例,它使用assertIn
方法检查指定网页的标题。
def test_paragraphs(self): self.driver.get("http://webcode.me") els = self.driver.find_elements_by_tag_name("p") self.assertIn('Today is a beautiful day', els[0].text) self.assertIn('Hello there', els[1].text)
在test_paragraphs
测试用例中,我们检查两个段落的内容。
def tearDown(self): self.driver.close()
在tearDown
方法中,我们关闭驱动程序。
if __name__ == "__main__": unittest.main()
使用main
方法,我们执行测试。
> py unittest_example.py .. ---------------------------------------------------------------------- Ran 2 tests in 13.273s OK
我们运行测试。unittest
显示一个点表示成功执行的测试用例,F表示失败的测试用例,E表示在测试执行期间发生的错误。
PythonSelenium与pytest
pytest
模块是一个用于测试Python应用程序的Python库。它是nose和unittest的替代品。
$ pip install pytest
我们安装了pytest
库。
pytest
在目录中查找test_*.py
或*_test.py
文件。在选定的文件中,pytest
在类之外查找带有test前缀的测试函数,并在带有Test
前缀的测试类中查找带有test前缀的测试方法(没有__init__
方法)).
#!/usr/bin/python import pytest from selenium.webdriver import Firefox from selenium.webdriver.firefox.options import Options @pytest.fixture def browser(): opts = Options() opts.headless = True driver = Firefox(options=opts) driver.implicitly_wait(5) yield driver # For cleanup, quit the driver driver.quit() def test_get_title(browser): browser.get("http://webcode.me") assert 'My html page' == browser.title
该示例显示了一个带有pytest
模块的简单测试用例。
@pytest.fixture def browser(): opts = Options() opts.headless = True driver = Firefox(options=opts) ...
我们定义了一个夹具。它设置Firefox驱动程序。
driver.implicitly_wait(5)
我们在尝试交互之前隐式等待元素准备就绪。
yield driver
使用yield
关键字,我们在设置结束时返回驱动程序对象。
def test_get_title(browser): browser.get("http://webcode.me") assert 'My html page' == browser.title
我们有一个检查网页标题的测试方法。它接收浏览器装置作为参数。
> pytest ============================== test session starts ============================== platform win32 -- Python 3.8.1, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 rootdir: C:\Users\Jano\Documents\python\SeleniumPytest collected 1 item tests\test_web.py . [100%] =============================== 1 passed in 6.31s ===============================
我们运行测试。
PythonSeleniumFlask示例
在下一个示例中,我们使用pytest
和Selenium为Flask网络应用程序创建一个测试用例。我们测试来自HTML表单的响应。
app.py ââââstatic â greet.html ââââtemplates â index.html ââââtests web_test.py
这是项目结构。
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Greet form</title> </head> <body> <p>Enter your name:</p> <form id="myform" action="greet"> <input name="name" type="text"> <button type="submit">Submit</button> </form> </body> </html>
我们在静态资源中有一个greet表单。表单向Flask应用程序发送一个文本值。
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Greeting</title> </head> <body> <p> Hello {{ name }} </p> </body> </html>
这是Flask模板文件,它向客户端返回一条消息。
#!/usr/bin/python from flask import Flask, render_template, request app = Flask(__name__) @app.route("/") def home(): return app.send_static_file('greet.html') @app.route("/greet") def greet(): username = request.args.get('name') return render_template('index.html', name=username) if __name__ == "__main__": app.run()
Flask应用有两种路由:一种用于主页,一种用于问候语。
#!/usr/bin/python import pytest from selenium.webdriver import Firefox from selenium.webdriver.firefox.options import Options from selenium.webdriver.support import expected_conditions as ec from selenium.webdriver.support.wait import WebDriverWait @pytest.fixture def browser(): opts = Options() opts.headless = True driver = Firefox(options=opts) driver.implicitly_wait(10) yield driver # For cleanup, quit the driver driver.quit() def test_greet_form(browser): user_name = "John" browser.get('http://localhost:5000/') form = browser.find_element_by_id("myform") name = browser.find_element_by_name("name") name.send_keys(user_name) form.submit() WebDriverWait(browser, 12).until(ec.url_matches('/greet'), 'Timed out waiting for response') content = browser.page_source print(content) assert 'Hello John' in content
web_test.py
包含问候语表单的测试用例。
def test_greet_form(browser): user_name = "John" browser.get('http://localhost:5000/') ...
首先,我们得到问候语形式。
form = browser.find_element_by_id("myform") name = browser.find_element_by_name("name") name.send_keys(user_name) form.submit()
我们检索表单的元素。我们将测试用户名添加到输入标签中并提交表单。
WebDriverWait(browser, 12).until(ec.url_matches('/greet'), 'Timed out waiting for response')
我们等待Flask重定向到/greet
路由。
content = browser.page_source print(content) assert 'Hello John' in content
我们收到响应并检查响应中的消息。
> set FLASK_APP=app.py > flask run
我们运行Flask应用程序。
> pytest ========================== test session starts =========================== platform win32 -- Python 3.8.1, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 rootdir: C:\Users\Jano\PycharmProjects\SeleniumPytestFlask collected 1 item tests\web_test.py . [100%] =========================== 1 passed in 12.44s ===========================
从不同的shell,我们执行pytest
。
在本教程中,我们使用了PythonSelenium框架。
列出所有Python教程。