准备好WebDriver后,让我们编写第一个Web测试!测试将是一个简单的DuckDuckGo搜索。DuckDuckGo是一个不跟踪用户数据的搜索引擎。就像任何其他搜索引擎一样,用户可以输入搜索短语并获得指向匹配网站的链接。
在编写自动化代码之前,最好总是以简单的语言编写测试过程。编写程序迫使我们首先考虑被测行为。这是我们的测试过程:
- 导航到DuckDuckGo主页
- 输入搜索词组
- 验证:
- 结果显示在结果页面上
- 搜索词出现在搜索栏中
- 至少一个搜索结果包含搜索短语
这是相当基本的,但涵盖了端到端的典型搜索行为。
代码
将以下测试功能添加到:tests/test_web.py
def test_basic_duckduckgo_search(browser):
URL = 'https://www.duckduckgo.com'
PHRASE = 'panda'
browser.get(URL)
search_input = browser.find_element_by_id('search_form_input_homepage')
search_input.send_keys(PHRASE Keys.RETURN)
link_divs = browser.find_elements_by_css_selector('#links > div')
assert len(link_divs) > 0
xpath = f"//div[@id='links']//*[contains(text(), '{PHRASE}')]"
results = browser.find_elements_by_xpath(xpath)
assert len(results) > 0
search_input = browser.find_element_by_id('search_form_input')
assert search_input.get_attribute('value') == PHRASE
该test_basic_duckduckgo_search
函数按照Arrange-Act-Assert模式执行我们的测试过程。请注意,测试函数声明了一个名为的参数browser
,该参数 与我们用于ChromeDriver设置和清除的固定装置相同。每次运行此测试时,pytest都会自动调用固定装置并注入WebDriver参考。然后,测试函数使用该browser
变量进行多个WebDriver调用。让我们看看这些调用是如何工作的。
URL = 'https://www.duckduckgo.com'
该测试将DuckDuckGo主页的URL声明为变量,以提高可读性和可维护性。
代码语言:javascript复制PHRASE = 'panda'
这是测试将使用的搜索短语。由于测试涵盖了“基本”搜索,因此该短语并不太重要。其他行使不同行为的测试应使用更复杂的短语。再次,测试将其声明在测试功能的顶部,以提高可读性和可维护性。
代码语言:javascript复制browser.get(URL)
测试的起点是DuckDuckGo主页。此调用将浏览器导航到给定的URL。被警告,虽然:此调用并 不会等待页面加载。它只是启动加载交互。
代码语言:javascript复制search_input = browser.find_element_by_id('search_form_input_homepage')
自动化Web交互的第一步是找到目标元素。元素可能会或可能不会出现在页面上。自动化必须使用 定位器 来查找元素(如果存在),然后构造一个代表该元素的对象。定位符的类型很多:ID,类名,CSS选择器,XPaths等。定位器将在页面上找到所有匹配的元素-可能不止一个。尝试使用最简单的定位器,该定位器将唯一地标识目标元素。
要编写定位器,您需要查看页面的HTML结构。Chrome DevTools可轻松检查任何实时页面的标记。只需右键单击页面,然后选择“检查”。您可以在“元素”选项卡上查看所有元素。对于我们的测试,我们想在DuckDuckGo主页上找到搜索输入字段。该元素的 id 属性值为“ search_form_input_homepage”,如下所示:
我们可以使用WebDriver的find_element_by_id
方法获取该元素。为search_input
变量分配了代表页面上搜索输入元素的对象。请记住,由于WebDriver实例具有隐式等待,因此最多等待10秒钟,搜索输入元素才会出现在页面上。
search_input.send_keys(PHRASE Keys.RETURN)
有了元素,我们就可以触发与它的交互。该send_keys
方法将一系列击键发送到搜索输入元素,就像人类用户会在键盘上键入一样。上面的呼叫发送搜索词组。最后的RETURN键提交搜索。
断言(1)
代码语言:javascript复制link_divs = browser.find_elements_by_css_selector('#links > div')
结果页面应显示一个div
ID为“ links”的div
元素,每个结果链接都有一个子元素。上面的CSS选择器可以找到所有这样的结果链接div。请注意,“元素”是复数–此调用将返回一个列表。
assert len(link_divs) > 0
测试必须验证搜索词是否确实出现了结果。此assert
语句确保在页面上至少找到一个结果链接。
断言(2)
代码语言:javascript复制xpath = f"//div[@id='links']//*[contains(text(), '{PHRASE}')]"
验证是否出现了一些结果很好,但是我们还应该验证结果是否与我们的搜索词匹配。我们可以使用XPath来精确定位包含文本中搜索短语的结果链接。XPath比名称和CSS选择器复杂,但它们也更强大。上面的XPath搜索div
ID为“ links”的链接,然后查找包含搜索短语文本的后代。
phrase_results = browser.find_elements_by_xpath(xpath)
此调用使用先前串联的XPath查找所有元素。我们可以将这两行合并为一,但是将这些行拆分起来更具可读性和Python风格。
代码语言:javascript复制assert len(phrase_results) > 0
像先前的断言一样,此断言确保至少找到一个元素。这是一个简单的健全性检查。它可以变得更强大-就像验证页面上的每个结果都包含搜索词组文本一样-但这很难。并非每个结果都可以包含搜索短语的确切文本。例如,某些可能具有大写字符。对于高级验证,定位器和逻辑将需要更加复杂。由于这是 基本的搜索测试,因此简单的断言就足够了。
断言(3)
代码语言:javascript复制search_input = browser.find_element_by_id('search_form_input')
最终断言验证搜索短语仍出现在搜索输入中。上面的行与Arrange阶段中的find元素调用相同 。它将再次找到搜索输入元素。我们为什么不能search_input
再次使用该对象?不幸的是,先前的元素已经 过时了。页面从搜索页面更改为结果页面。即使元素看起来相同,也有所不同,并且还需要一个新的定位器。因此,我们需要重新获取它。
assert search_input.get_attribute('value') == PHRASE
键入输入元素的文本可作为其“值”属性访问。该行断言“值”属性等于搜索词组。它验证该短语没有消失。
查看并运行Web测试
现在,其完整代码应如下所示(为清晰起见,附加了注释):tests/test_web.py
"""
This module contains web test cases for the tutorial.
Tests use Selenium WebDriver with Chrome and ChromeDriver.
The fixtures set up and clean up the ChromeDriver instance.
"""
import pytest
from selenium.webdriver import Chrome
from selenium.webdriver.common.keys import Keys
@pytest.fixture
def browser():
# Initialize ChromeDriver
driver = Chrome()
# Wait implicitly for elements to be ready before attempting interactions
driver.implicitly_wait(10)
# Return the driver object at the end of setup
yield driver
# For cleanup, quit the driver
driver.quit()
def test_basic_duckduckgo_search(browser):
# Set up some test case data
URL = 'https://www.duckduckgo.com'
PHRASE = 'panda'
# Navigate to the DuckDuckGo home page
browser.get(URL)
# Find the search input element
# In the DOM, it has an 'id' attribute of 'search_form_input_homepage'
search_input = browser.find_element_by_id('search_form_input_homepage')
# Send a search phrase to the input and hit the RETURN key
search_input.send_keys(PHRASE Keys.RETURN)
# Verify that results appear on the results page
link_divs = browser.find_elements_by_css_selector('#links > div')
assert len(link_divs) > 0
# Verify that at least one search result contains the search phrase
xpath = f"//div[@id='links']//*[contains(text(), '{PHRASE}')]"
phrase_results = browser.find_elements_by_xpath(xpath)
assert len(phrase_results) > 0
# Verify that the search phrase is the same
search_input = browser.find_element_by_id('search_form_input')
assert search_input.get_attribute('value') == PHRASE
现在,运行测试以确保它可以运行:
代码语言:javascript复制$ pipenv run python -m pytest
============================= test session starts ==============================
platform darwin -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.12.0
rootdir: /Users/andylpk247/Programming/automation-panda/python-webui-testing
collected 9 items
tests/test_math.py ........ [ 88%]
tests/test_web.py . [100%]
=========================== 9 passed in 6.10 seconds ===========================
网络测试运行时,它将打开Google Chrome。您可以观看它自动输入搜索短语,等待结果页面,然后退出浏览器。整齐!
如果测试无法运行,请检查以下内容:
- 测试计算机是否已安装Chrome?
- ChromeDriver是否在系统路径上?
- ChromeDriver版本与Chrome版本匹配吗?
- 是否有文件系统权限问题?
- 防火墙是否阻止了任何端口?
- 测试代码正确吗?