在pytest的conftest.py中设置测试执行顺序,参数化测试
Setting up the test execution sequence in conftest.py of pytest, parametrized testing
conftest.py:
def pytest_collection_modifyitems(config, items):
def param_part(item):
# check for the wanted module and test class
if item.nodeid.startswith("test_urls.py::TestSSL::"):
# find the start of the parameter part in the nodeid
index = item.nodeid.find('[')
if index > 0:
# sort by parameter name
return item.name[item.nodeid.index('['):]
# for all other cases, sort by node id as usual
return item.nodeid
# re-order the items using the param_part function as key
items[:] = sorted(items, key=param_part)
test_urls.py:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from allure_commons.types import AttachmentType
import pytest
import logging
import allure
driver = webdriver.Chrome(executable_path=r'C:\chromedriver.exe')
# Logger
logging.basicConfig(filename="C:/LPsLogs/test.log",
format='%(asctime)s: %(levelname)s: %(message)s',
datefmt='%m/%d/%Y %H:%M:%S')
logger = logging.getLogger()
logger.setLevel(logging.INFO)
wait = WebDriverWait(driver, 2)
driver.implicitly_wait(2)
ec = EC
goxp = driver.find_element_by_xpath
goid = driver.find_element_by_id
keys = Keys
original_window = driver.current_window_handle
# Urls
sslurl = "https://www.sslshopper.com/ssl-checker.html"
# Locators
# xpath
sslpch = "//h1"
u1chb1 = "//div[@id='checkData']/descendant::td[1]"
u1chb2 = "//div[@id='checkData']/descendant::td[3]"
u1chb3 = "//div[@id='checkData']/descendant::td[5]"
u1chb4 = "//div[@id='checkData']/descendant::td[7]"
u1chb5 = "//div[@id='checkData']/descendant::td[11]"
u1chb6 = "//div[@id='checkData']/descendant::td[15]"
# id
hostname = "hostname"
expdate = "cert_expiration_days"
@allure.severity(allure.severity_level.BLOCKER)
def test_go_ca_sslcheck():
logger.info("Testing started")
driver.maximize_window()
driver.get(sslurl)
wait.until(EC.visibility_of_element_located((By.XPATH, sslpch)))
sslchecker = driver.find_element_by_xpath(sslpch).text
if sslchecker == 'SSL Checker':
assert True
else:
logging.error('Error - def test_go_sslcheck module', exc_info=True)
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
assert False
@pytest.mark.parametrize("url", ["https://google.com",
"https://expired.badssl.com"
])
class TestSSL:
@allure.severity(allure.severity_level.CRITICAL)
def test_url_input(self, url):
try:
input_hostname = goid(hostname)
input_hostname.send_keys(url)
input_hostname.send_keys(keys.ENTER)
# time.sleep(2)
print(f"{url} has been entered")
assert True
input_hostname.clear()
except (Exception, NameError, AssertionError):
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
logging.error('Error - url_input module', exc_info=True)
assert False
@allure.severity(allure.severity_level.CRITICAL)
def test_url_checkbox1(self, url):
wait.until(EC.visibility_of_element_located((By.XPATH, u1chb1)))
u1chb1ch = driver.find_element_by_xpath(u1chb1).get_attribute('class')
if u1chb1ch == 'passed':
print(f"{url} - test_url_checkbox1 - PASS")
assert True
else:
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
logging.error(f'{url} - checkbox 1 - FAILED', exc_info=True)
assert False
@allure.severity(allure.severity_level.CRITICAL)
def test_url_checkbox2(self, url):
wait.until(EC.visibility_of_element_located((By.XPATH, u1chb2)))
u1chb2ch = driver.find_element_by_xpath(u1chb2).get_attribute('class')
if u1chb2ch == 'passed':
print(f"{url} - test_url_checkbox2 - PASS")
assert True
else:
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
logging.error(f'{url} - checkbox 2 - FAILED', exc_info=True)
assert False
@allure.severity(allure.severity_level.CRITICAL)
def test_url_checkbox3(self, url):
wait.until(EC.visibility_of_element_located((By.XPATH, u1chb3)))
u1chb3ch = driver.find_element_by_xpath(u1chb3).get_attribute('class')
if u1chb3ch == 'passed':
print(f"{url} - test_url_checkbox3 - PASS")
assert True
else:
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
logging.error(f'{url} - checkbox 3 - FAILED', exc_info=True)
assert False
@allure.severity(allure.severity_level.CRITICAL)
def test_url_checkbox4(self, url):
wait.until(EC.visibility_of_element_located((By.XPATH, u1chb4)))
u1chb4ch = driver.find_element_by_xpath(u1chb4).get_attribute('class')
if u1chb4ch == 'passed':
print(f"{url} - test_url_checkbox4 - PASS")
assert True
else:
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
logging.error(f'{url} - checkbox 4 - FAILED', exc_info=True)
assert False
@allure.severity(allure.severity_level.CRITICAL)
def test_url_checkbox5(self, url):
wait.until(EC.visibility_of_element_located((By.XPATH, u1chb5)))
u1chb5ch = driver.find_element_by_xpath(u1chb5).get_attribute('class')
if u1chb5ch == 'passed':
print(f"{url} - test_url_checkbox5 - PASS")
assert True
else:
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
logging.error(f'{url} - checkbox 5 - FAILED', exc_info=True)
assert False
@allure.severity(allure.severity_level.CRITICAL)
def test_url_checkbox6(self, url):
wait.until(EC.visibility_of_element_located((By.XPATH, u1chb6)))
u1chb6ch = driver.find_element_by_xpath(u1chb6).get_attribute('class')
if u1chb6ch == 'passed':
print(f"{url} - test_url_checkbox6 - PASS")
assert True
else:
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
logging.error(f'{url} - checkbox 6 - FAILED', exc_info=True)
assert False
@allure.severity(allure.severity_level.NORMAL)
def test_url_expdate_w(self, url):
expdatech = driver.find_element_by_id(expdate).text
if int(expdatech) > 7:
print(f"{url} - expdate more than 7 days - PASS")
assert True
else:
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
print(expdatech)
logging.warning(f"{url} SSL certificate will expire in less than 7 days, days left: {expdatech}", exc_info=True)
assert False
# def test_close_browser():
try:
logger.info("Testing finished")
driver.close()
assert True
except (Exception, NameError, AssertionError):
logging.error('Error - close_browser module', exc_info=True)
assert False
结果:
测试执行顺序 now - https://prnt.sc/ttw4or
conftest 还按名称(字母)对测试进行排序,我需要删除此依赖项。
目标结果:
测试执行顺序 需要 - test_go_ca_sslcheck() > class 第一次迭代 url > class 第二次迭代 url , 直到他们结束 > def test_close_browser()
注:
也许有更简单的方法来实现目标,请详细描述,我的知识极其有限。提前致谢!
如果我现在理解正确的话,您不想更改默认排序顺序,参数化测试除外。
这是一个稍微复杂一点的改编版本,可以做到这一点(我试图添加足够的评论来解释它):
def pytest_collection_modifyitems(config, items):
def param_part(item):
index = item.name.find('[')
if index > 0:
# revert the name and parameter parts, so tests are sorted by
# parameter first and name second
return (item.name[item.name.index('['):]
+ item.name[:item.name.index('[')])
return item.name
class_id = "test_urls.py::TestSSL::"
# find the first test in the class to be sorted
start_index = next((i for (i, item) in enumerate(items)
if item.nodeid.startswith(class_id)), -1)
if start_index != -1:
# ... and the first test after the class
# (have to start the first at start_index)
end_index = next((i + start_index for (i, item)
in enumerate(items[start_index:])
if not item.nodeid.startswith(class_id)), -1)
# sort only the items in the class and let the rest alone
items[start_index:end_index] = sorted(items[start_index:end_index],
key=param_part)
# for any other tests without our class we leave the items alone
这给出了 pytest -vv test_urls.py
的输出:
...
test_urls.py::test_go_ca_sslcheck PASSED [ 5%]
test_urls.py::TestSSL::test_url_checkbox1[https://expired.badssl.com] PASSED [ 11%]
test_urls.py::TestSSL::test_url_checkbox2[https://expired.badssl.com] PASSED [ 16%]
test_urls.py::TestSSL::test_url_checkbox3[https://expired.badssl.com] PASSED [ 22%]
test_urls.py::TestSSL::test_url_checkbox4[https://expired.badssl.com] PASSED [ 27%]
test_urls.py::TestSSL::test_url_checkbox5[https://expired.badssl.com] PASSED [ 33%]
test_urls.py::TestSSL::test_url_checkbox6[https://expired.badssl.com] PASSED [ 38%]
test_urls.py::TestSSL::test_url_expdate_w[https://expired.badssl.com] PASSED [ 44%]
test_urls.py::TestSSL::test_url_input[https://expired.badssl.com] PASSED [ 50%]
test_urls.py::TestSSL::test_url_checkbox1[https://google.com] PASSED [ 55%]
test_urls.py::TestSSL::test_url_checkbox2[https://google.com] PASSED [ 61%]
test_urls.py::TestSSL::test_url_checkbox3[https://google.com] PASSED [ 66%]
test_urls.py::TestSSL::test_url_checkbox4[https://google.com] PASSED [ 72%]
test_urls.py::TestSSL::test_url_checkbox5[https://google.com] PASSED [ 77%]
test_urls.py::TestSSL::test_url_checkbox6[https://google.com] PASSED [ 83%]
test_urls.py::TestSSL::test_url_expdate_w[https://google.com] PASSED [ 88%]
test_urls.py::TestSSL::test_url_input[https://google.com] PASSED [ 94%]
test_urls.py::test_close_browser PASSED [100%]
================================================= 18 passed in 0.16s ==================================================
conftest.py:
def pytest_collection_modifyitems(config, items):
def param_part(item):
# check for the wanted module and test class
if item.nodeid.startswith("test_urls.py::TestSSL::"):
# find the start of the parameter part in the nodeid
index = item.nodeid.find('[')
if index > 0:
# sort by parameter name
return item.name[item.nodeid.index('['):]
# for all other cases, sort by node id as usual
return item.nodeid
# re-order the items using the param_part function as key
items[:] = sorted(items, key=param_part)
test_urls.py:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from allure_commons.types import AttachmentType
import pytest
import logging
import allure
driver = webdriver.Chrome(executable_path=r'C:\chromedriver.exe')
# Logger
logging.basicConfig(filename="C:/LPsLogs/test.log",
format='%(asctime)s: %(levelname)s: %(message)s',
datefmt='%m/%d/%Y %H:%M:%S')
logger = logging.getLogger()
logger.setLevel(logging.INFO)
wait = WebDriverWait(driver, 2)
driver.implicitly_wait(2)
ec = EC
goxp = driver.find_element_by_xpath
goid = driver.find_element_by_id
keys = Keys
original_window = driver.current_window_handle
# Urls
sslurl = "https://www.sslshopper.com/ssl-checker.html"
# Locators
# xpath
sslpch = "//h1"
u1chb1 = "//div[@id='checkData']/descendant::td[1]"
u1chb2 = "//div[@id='checkData']/descendant::td[3]"
u1chb3 = "//div[@id='checkData']/descendant::td[5]"
u1chb4 = "//div[@id='checkData']/descendant::td[7]"
u1chb5 = "//div[@id='checkData']/descendant::td[11]"
u1chb6 = "//div[@id='checkData']/descendant::td[15]"
# id
hostname = "hostname"
expdate = "cert_expiration_days"
@allure.severity(allure.severity_level.BLOCKER)
def test_go_ca_sslcheck():
logger.info("Testing started")
driver.maximize_window()
driver.get(sslurl)
wait.until(EC.visibility_of_element_located((By.XPATH, sslpch)))
sslchecker = driver.find_element_by_xpath(sslpch).text
if sslchecker == 'SSL Checker':
assert True
else:
logging.error('Error - def test_go_sslcheck module', exc_info=True)
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
assert False
@pytest.mark.parametrize("url", ["https://google.com",
"https://expired.badssl.com"
])
class TestSSL:
@allure.severity(allure.severity_level.CRITICAL)
def test_url_input(self, url):
try:
input_hostname = goid(hostname)
input_hostname.send_keys(url)
input_hostname.send_keys(keys.ENTER)
# time.sleep(2)
print(f"{url} has been entered")
assert True
input_hostname.clear()
except (Exception, NameError, AssertionError):
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
logging.error('Error - url_input module', exc_info=True)
assert False
@allure.severity(allure.severity_level.CRITICAL)
def test_url_checkbox1(self, url):
wait.until(EC.visibility_of_element_located((By.XPATH, u1chb1)))
u1chb1ch = driver.find_element_by_xpath(u1chb1).get_attribute('class')
if u1chb1ch == 'passed':
print(f"{url} - test_url_checkbox1 - PASS")
assert True
else:
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
logging.error(f'{url} - checkbox 1 - FAILED', exc_info=True)
assert False
@allure.severity(allure.severity_level.CRITICAL)
def test_url_checkbox2(self, url):
wait.until(EC.visibility_of_element_located((By.XPATH, u1chb2)))
u1chb2ch = driver.find_element_by_xpath(u1chb2).get_attribute('class')
if u1chb2ch == 'passed':
print(f"{url} - test_url_checkbox2 - PASS")
assert True
else:
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
logging.error(f'{url} - checkbox 2 - FAILED', exc_info=True)
assert False
@allure.severity(allure.severity_level.CRITICAL)
def test_url_checkbox3(self, url):
wait.until(EC.visibility_of_element_located((By.XPATH, u1chb3)))
u1chb3ch = driver.find_element_by_xpath(u1chb3).get_attribute('class')
if u1chb3ch == 'passed':
print(f"{url} - test_url_checkbox3 - PASS")
assert True
else:
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
logging.error(f'{url} - checkbox 3 - FAILED', exc_info=True)
assert False
@allure.severity(allure.severity_level.CRITICAL)
def test_url_checkbox4(self, url):
wait.until(EC.visibility_of_element_located((By.XPATH, u1chb4)))
u1chb4ch = driver.find_element_by_xpath(u1chb4).get_attribute('class')
if u1chb4ch == 'passed':
print(f"{url} - test_url_checkbox4 - PASS")
assert True
else:
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
logging.error(f'{url} - checkbox 4 - FAILED', exc_info=True)
assert False
@allure.severity(allure.severity_level.CRITICAL)
def test_url_checkbox5(self, url):
wait.until(EC.visibility_of_element_located((By.XPATH, u1chb5)))
u1chb5ch = driver.find_element_by_xpath(u1chb5).get_attribute('class')
if u1chb5ch == 'passed':
print(f"{url} - test_url_checkbox5 - PASS")
assert True
else:
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
logging.error(f'{url} - checkbox 5 - FAILED', exc_info=True)
assert False
@allure.severity(allure.severity_level.CRITICAL)
def test_url_checkbox6(self, url):
wait.until(EC.visibility_of_element_located((By.XPATH, u1chb6)))
u1chb6ch = driver.find_element_by_xpath(u1chb6).get_attribute('class')
if u1chb6ch == 'passed':
print(f"{url} - test_url_checkbox6 - PASS")
assert True
else:
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
logging.error(f'{url} - checkbox 6 - FAILED', exc_info=True)
assert False
@allure.severity(allure.severity_level.NORMAL)
def test_url_expdate_w(self, url):
expdatech = driver.find_element_by_id(expdate).text
if int(expdatech) > 7:
print(f"{url} - expdate more than 7 days - PASS")
assert True
else:
allure.attach(driver.get_screenshot_as_png(), name="testLoginScreen", attachment_type=AttachmentType.PNG)
print(expdatech)
logging.warning(f"{url} SSL certificate will expire in less than 7 days, days left: {expdatech}", exc_info=True)
assert False
# def test_close_browser():
try:
logger.info("Testing finished")
driver.close()
assert True
except (Exception, NameError, AssertionError):
logging.error('Error - close_browser module', exc_info=True)
assert False
结果: 测试执行顺序 now - https://prnt.sc/ttw4or conftest 还按名称(字母)对测试进行排序,我需要删除此依赖项。
目标结果: 测试执行顺序 需要 - test_go_ca_sslcheck() > class 第一次迭代 url > class 第二次迭代 url , 直到他们结束 > def test_close_browser()
注: 也许有更简单的方法来实现目标,请详细描述,我的知识极其有限。提前致谢!
如果我现在理解正确的话,您不想更改默认排序顺序,参数化测试除外。
这是一个稍微复杂一点的改编版本,可以做到这一点(我试图添加足够的评论来解释它):
def pytest_collection_modifyitems(config, items):
def param_part(item):
index = item.name.find('[')
if index > 0:
# revert the name and parameter parts, so tests are sorted by
# parameter first and name second
return (item.name[item.name.index('['):]
+ item.name[:item.name.index('[')])
return item.name
class_id = "test_urls.py::TestSSL::"
# find the first test in the class to be sorted
start_index = next((i for (i, item) in enumerate(items)
if item.nodeid.startswith(class_id)), -1)
if start_index != -1:
# ... and the first test after the class
# (have to start the first at start_index)
end_index = next((i + start_index for (i, item)
in enumerate(items[start_index:])
if not item.nodeid.startswith(class_id)), -1)
# sort only the items in the class and let the rest alone
items[start_index:end_index] = sorted(items[start_index:end_index],
key=param_part)
# for any other tests without our class we leave the items alone
这给出了 pytest -vv test_urls.py
的输出:
...
test_urls.py::test_go_ca_sslcheck PASSED [ 5%]
test_urls.py::TestSSL::test_url_checkbox1[https://expired.badssl.com] PASSED [ 11%]
test_urls.py::TestSSL::test_url_checkbox2[https://expired.badssl.com] PASSED [ 16%]
test_urls.py::TestSSL::test_url_checkbox3[https://expired.badssl.com] PASSED [ 22%]
test_urls.py::TestSSL::test_url_checkbox4[https://expired.badssl.com] PASSED [ 27%]
test_urls.py::TestSSL::test_url_checkbox5[https://expired.badssl.com] PASSED [ 33%]
test_urls.py::TestSSL::test_url_checkbox6[https://expired.badssl.com] PASSED [ 38%]
test_urls.py::TestSSL::test_url_expdate_w[https://expired.badssl.com] PASSED [ 44%]
test_urls.py::TestSSL::test_url_input[https://expired.badssl.com] PASSED [ 50%]
test_urls.py::TestSSL::test_url_checkbox1[https://google.com] PASSED [ 55%]
test_urls.py::TestSSL::test_url_checkbox2[https://google.com] PASSED [ 61%]
test_urls.py::TestSSL::test_url_checkbox3[https://google.com] PASSED [ 66%]
test_urls.py::TestSSL::test_url_checkbox4[https://google.com] PASSED [ 72%]
test_urls.py::TestSSL::test_url_checkbox5[https://google.com] PASSED [ 77%]
test_urls.py::TestSSL::test_url_checkbox6[https://google.com] PASSED [ 83%]
test_urls.py::TestSSL::test_url_expdate_w[https://google.com] PASSED [ 88%]
test_urls.py::TestSSL::test_url_input[https://google.com] PASSED [ 94%]
test_urls.py::test_close_browser PASSED [100%]
================================================= 18 passed in 0.16s ==================================================