Environment: Python 2 7.10, selenium3.141.0, pytest4.6.6, pytest-html1.22.0, Windows-7-6.1.7601-SP1
characteristic:
- Secondary encapsulation of selenium makes it more convenient to write Case.
- Adopt PO design idea, one page per page Py, in which the elements and operation methods are defined; In TestCase, directly call the operation method encapsulated in the page to operate the page.
- Start the browser only once in a test to save time and improve efficiency (the one suitable for the company's business is the best).
- Enhance the content of pytest HTML report and add failure screenshots, use case description columns and operation logs.
- Command line parameters are supported.
- Support sending reports by mail.
Directory structure:
- config
- config.py: store global variables, various configurations, driver s, etc
- drive: Browser driver files, such as chromedriver exe
- file
- Download: download folder
- Screenshot: screenshot folder
- Upload: upload folder
- page_object: one for each page py to store page objects and operation methods
- base_page.py: basic page, which encapsulates various operations of selenium
- hao123_page.py: hao123 page
- home_page.py: Baidu home page
- news_page.py: News Home Page
- search_page.py: search results page
- report:
- report.html: report generated by pytest HTML
- test_case
- conftest.py: pytest unique file, in which the screenshot of report failure and the column of use case description are added
- test_home.py: Baidu home page test case
- test_news.py: test case of NEWS HOMEPAGE
- test_search.py: search results page test case
- util: Toolkit
- log.py: encapsulates the log module
- mail.py: encapsulates the mail module. To use the send report mail function, you need to set relevant configurations, such as user name and password
- run.py: as a run entry, it encapsulates the pytest run command; Realize that all test cases share a driver; The operation parameterization is realized (combined with Jenkins); log configuration initialization; You can configure sending report mail.
config.py code implementation:
1. Define a global dictionary to store global variables. key is the variable name and value is the variable value. Parameters can be passed across files and use cases.
2. set_value,get_value is used to save and retrieve global variables respectively.
1 # coding=utf-8 2 3 import os 4 5 6 def init(): 7 global _global_dict 8 _global_dict = {} 9 10 # Code root directory 11 root_dir = os.getcwd() 12 13 # Directory where the program is stored 14 _global_dict['root_path'] = root_dir 15 # Store normal screenshot folder 16 _global_dict['screenshot_path'] = "{}\\file\\screenshot\\".format(root_dir) 17 # Download folder 18 _global_dict['download_path'] = "{}\\file\\download\\".format(root_dir) 19 # Upload folder 20 _global_dict['upload_path'] = "{}\\file\\upload\\".format(root_dir) 21 # Storage report path 22 _global_dict['report_path'] = "{}\\report\\".format(root_dir) 23 24 # Save driver 25 _global_dict['driver'] = None 26 27 # Set the web address and home page of the running environment 28 _global_dict['site'] = 'https://www.baidu.com/' 29 # The operating environment is preview by default and can be set to product 30 _global_dict['environment'] = 'preview' 31 32 33 def set_value(name, value): 34 """ 35 Modify the value of the global variable 36 :param name: Variable name 37 :param value: Variable value 38 """ 39 _global_dict[name] = value 40 41 42 def get_value(name, def_val='no_value'): 43 """ 44 Gets the value of the global variable 45 :param name: Variable name 46 :param def_val: Default variable value 47 :return: Returns the value of a variable when it exists, otherwise'no_value' 48 """ 49 try: 50 return _global_dict[name] 51 except KeyError: 52 return def_val
log.py code implementation: encapsulated log module
1 # coding=utf-8 2 3 import logging 4 import time 5 import config.config as cf 6 7 8 class Logger(object): 9 """Encapsulated log module""" 10 11 def __init__(self, logger, cmd_level=logging.DEBUG, file_level=logging.DEBUG): 12 try: 13 self.logger = logging.getLogger(logger) 14 self.logger.setLevel(logging.DEBUG) # Sets the default level for log output 15 '''pytest Reports can be automatically log Integrate it into the report, and you don't have to set and save it separately 16 # Log output format 17 fmt = logging.Formatter( 18 '%(asctime)s[%(levelname)s]\t%(message)s') 19 # Log file name 20 curr_time = time.strftime("%Y-%m-%d %H.%M.%S") 21 log_path = cf.get_value('log_path') 22 self.log_file = '{}log{}.txt'.format(log_path, curr_time) 23 # Set console output 24 sh = logging.StreamHandler() 25 sh.setFormatter(fmt) 26 sh.setLevel(cmd_level) 27 # Set file output 28 fh = logging.FileHandler(self.log_file) 29 fh.setFormatter(fmt) 30 fh.setLevel(file_level) 31 # Add log output method 32 self.logger.addHandler(sh) 33 self.logger.addHandler(fh) 34 ''' 35 except Exception as e: 36 raise e 37 38 def debug(self, msg): 39 self.logger.debug(msg) 40 41 def info(self, msg): 42 self.logger.info(msg) 43 44 def error(self, msg): 45 self.logger.error(msg) 46 47 def warning(self, msg): 48 self.logger.warning(msg)
mail.py code implementation: for the encapsulated mail module, the report HTML file will be sent as an attachment. Here, you need to change all the top four variables to your own.
1 # coding=utf-8 2 3 import smtplib 4 from email.mime.text import MIMEText 5 from email.mime.multipart import MIMEMultipart 6 from email.header import Header 7 import config.config as cf 8 9 10 def send_mail(sendto): 11 """ 12 Send mail 13 :param sendto:Recipient list, such as['22459496@qq.com'] 14 """ 15 mail_host = 'smtp.sohu.com' # Mailbox server address 16 username = 'test@sohu.com' # Mailbox user name 17 password = 'test' # Mailbox password 18 receivers = sendto # addressee 19 20 # Create an instance with attachments 21 message = MIMEMultipart() 22 message['From'] = Header(u'UI automation', 'utf-8') 23 message['subject'] = Header(u'UI Automated test results', 'utf-8') # Mail title 24 message.attach(MIMEText(u'See Annex for test results', 'plain', 'utf-8'))# Message body 25 # Construction attachment 26 report_root = cf.get_value('report_path') # Get report path 27 report_file = 'report.html' # Report file name 28 att1 = MIMEText(open(report_root + report_file, 'rb').read(), 'base64', 'utf-8') 29 att1["Content-Type"] = 'application/octet-stream' 30 att1["Content-Disposition"] = 'attachment; filename={}'.format(report_file) 31 message.attach(att1) 32 33 try: 34 smtp = smtplib.SMTP() 35 smtp.connect(mail_host, 25) # 25 is the SMTP port number 36 smtp.login(username, password) 37 smtp.sendmail(username, receivers, message.as_string()) 38 print u'Mail sent successfully' 39 except Exception, e: 40 print u'Mail sending failed' 41 raise e
base_page.py code implementation: it encapsulates the common operations of selenium as the base class of all page classes.
1 # coding=utf-8 2 3 from selenium.common.exceptions import TimeoutException 4 from selenium.webdriver.support.ui import WebDriverWait 5 from selenium.webdriver.common.keys import Keys 6 from selenium.webdriver.common.action_chains import ActionChains 7 import os 8 import inspect 9 import config.config as cf 10 import logging 11 import time 12 13 log = logging.getLogger('szh.BasePage') 14 15 16 class BasePage(object): 17 def __init__(self): 18 self.driver = cf.get_value('driver') # Get driver from global variable 19 20 def split_locator(self, locator): 21 """ 22 Explode positioning expressions, such as'css,.username',Return after splitting'css selector'And positioning expressions'.username'(class by username Element of) 23 :param locator: Positioning method+Positioning expression combination string, such as'css,.username' 24 :return: locator_dict[by], value:Returns the positioning method and positioning expression 25 """ 26 by = locator.split(',')[0] 27 value = locator.split(',')[1] 28 locator_dict = { 29 'id': 'id', 30 'name': 'name', 31 'class': 'class name', 32 'tag': 'tag name', 33 'link': 'link text', 34 'plink': 'partial link text', 35 'xpath': 'xpath', 36 'css': 'css selector', 37 } 38 if by not in locator_dict.keys(): 39 raise NameError("wrong locator!'id','name','class','tag','link','plink','xpath','css',exp:'id,username'") 40 return locator_dict[by], value 41 42 def wait_element(self, locator, sec=30): 43 """ 44 Wait for the element to appear 45 :param locator: Positioning method+Positioning expression combination string, separated by commas, such as'css,.username' 46 :param sec:Wait seconds 47 """ 48 by, value = self.split_locator(locator) 49 try: 50 WebDriverWait(self.driver, sec, 1).until(lambda x: x.find_element(by=by, value=value), 51 message='element not found!!!') 52 log.info(u'Waiting element:%s' % locator) 53 return True 54 except TimeoutException: 55 return False 56 except Exception, e: 57 raise e 58 59 def get_element(self, locator, sec=60): 60 """ 61 Get an element 62 :param locator: Positioning method+Positioning expression combination string, separated by commas, such as'css,.username' 63 :param sec:Wait seconds 64 :return: Element can be found and returned element Object, otherwise return False 65 """ 66 if self.wait_element(locator, sec): 67 by, value = self.split_locator(locator) 68 print by, value 69 try: 70 element = self.driver.find_element(by=by, value=value) 71 log.info(u'Get element:%s' % locator) 72 return element 73 except Exception, e: 74 raise e 75 else: 76 return False 77 78 def get_elements(self, locator): 79 """ 80 Get a set of elements 81 :param locator: Positioning method+Positioning expression combination string, separated by commas, such as'css,.username' 82 :return: elements 83 """ 84 by, value = self.split_locator(locator) 85 try: 86 elements = WebDriverWait(self.driver, 60, 1).until(lambda x: x.find_elements(by=by, value=value)) 87 log.info(u'Get element list:%s' % locator) 88 return elements 89 except Exception, e: 90 raise e 91 92 def open(self, url): 93 """ 94 Open URL 95 :param url: URL connection 96 """ 97 self.driver.get(url) 98 log.info(u'Open web address:%s' % url) 99 100 def clear(self, locator): 101 """ 102 Clear contents of element 103 :param locator: Positioning method+Positioning expression combination string, separated by commas, such as'css,.username' 104 """ 105 self.get_element(locator).clear() 106 log.info(u'Empty content:%s' % locator) 107 108 def type(self, locator, text): 109 """ 110 Enter content in element 111 :param locator: Positioning method+Positioning expression combination string, separated by commas, such as'css,.username' 112 :param text: Input content 113 """ 114 self.get_element(locator).send_keys(text) 115 log.info(u'Directional element %s Enter text:%s' % (locator, text)) 116 117 def enter(self, locator): 118 """ 119 Press enter on the element 120 :param locator: Positioning method+Positioning expression combination string, separated by commas, such as'css,.username' 121 """ 122 self.get_element(locator).send_keys(Keys.ENTER) 123 log.info(u'In element %s Press enter up' % locator) 124 125 def click(self, locator): 126 """ 127 Click on the element 128 :param locator: Positioning method+Positioning expression combination string, separated by commas, such as'css,.username' 129 """ 130 self.get_element(locator).click() 131 log.info(u'Click on the element:%s' % locator) 132 133 def right_click(self, locator): 134 """ 135 Right click the element 136 :param locator: Positioning method+Positioning expression combination string, separated by commas, such as'css,.username' 137 """ 138 element = self.get_element(locator) 139 ActionChains(self.driver).context_click(element).perform() 140 log.info(u'Right click on the element:%s' % locator) 141 142 def double_click(self, locator): 143 """ 144 Double click the element 145 :param locator: Positioning method+Positioning expression combination string, separated by commas, such as'css,.username' 146 """ 147 element = self.get_element(locator) 148 ActionChains(self.driver).double_click(element).perform() 149 log.info(u'Double click on the element:%s' % locator) 150 151 def move_to_element(self, locator): 152 """ 153 Point the mouse at the element 154 :param locator: Positioning method+Positioning expression combination string, separated by commas, such as'css,.username' 155 """ 156 element = self.get_element(locator) 157 ActionChains(self.driver).move_to_element(element).perform() 158 log.info(u'Point to element%s' % locator) 159 160 def drag_and_drop(self, locator, target_locator): 161 """ 162 Drag an element to another element location 163 :param locator: The anchor of the element to drag 164 :param target_locator: Positioning of target location element 165 """ 166 element = self.get_element(locator) 167 target_element = self.get_element(target_locator) 168 ActionChains(self.driver).drag_and_drop(element, target_element).perform() 169 log.info(u'Put element %s Drag to element %s' % (locator, target_locator)) 170 171 def drag_and_drop_by_offset(self, locator, xoffset, yoffset): 172 """ 173 Drag an element down to the right x,y Offsets 174 :param locator: Positioning method+Positioning expression combination string, separated by commas, such as'css,.username' 175 :param xoffset: X offset to move to 176 :param yoffset: Y offset to move to 177 """ 178 element = self.get_element(locator) 179 ActionChains(self.driver).drag_and_drop_by_offset(element, xoffset, yoffset).perform() 180 log.info(u'Put element %s Drag to coordinates:%s %s' % (locator, xoffset, yoffset)) 181 182 def click_link(self, text): 183 """ 184 Search by part of the link text and click the link 185 :param text: Partial text of the link 186 """ 187 self.get_element('plink,' + text).click() 188 log.info(u'Click Connect:%s' % text) 189 190 def alert_text(self): 191 """ 192 return alert text 193 :return: alert text 194 """ 195 log.info(u'Get pop-up text:%s' % self.driver.switch_to.alert.text) 196 return self.driver.switch_to.alert.text 197 198 def alert_accept(self): 199 """ 200 alert Point confirmation 201 """ 202 self.driver.switch_to.alert.accept() 203 log.info(u'Click the pop-up box to confirm') 204 205 def alert_dismiss(self): 206 """ 207 alert Point cancel 208 """ 209 self.driver.switch_to.alert.dismiss() 210 log.info(u'Click the pop-up box to cancel') 211 212 def get_attribute(self, locator, attribute): 213 """ 214 Returns the value of an attribute of an element 215 :param locator: Positioning method+Positioning expression combination string, separated by commas, such as'css,.username' 216 :param attribute: Attribute name 217 :return: Attribute value 218 """ 219 value = self.get_element(locator).get_attribute(attribute) 220 log.info(u'Get element %s Attribute value for %s Is:%s' % (locator, attribute, value)) 221 return value 222 223 def get_ele_text(self, locator): 224 """ 225 Returns the text of the element 226 :param locator: Positioning method+Positioning expression combination string, separated by commas, such as'css,.username' 227 :return: The text of the element 228 """ 229 log.info(u'Get element %s The text is:%s' % (locator, self.get_element(locator).text)) 230 return self.get_element(locator).text 231 232 def frame_in(self, locator): 233 """ 234 get into frame 235 :param locator: Positioning method+Positioning expression combination string, such as'css,.username' 236 """ 237 e = self.get_element(locator) 238 self.driver.switch_to.frame(e) 239 log.info(u'get into frame: %s' % locator) 240 241 def frame_out(self): 242 """ 243 Return to main document 244 """ 245 self.driver.switch_to.default_content() 246 log.info(u'sign out frame Return to default document') 247 248 def open_new_window_by_locator(self, locator): 249 """ 250 Click the element to open a new window and switch the handle to the new window 251 :param locator: Positioning method+Positioning expression combination string, such as'css,.username' 252 """ 253 self.get_element(locator).click() 254 self.driver.switch_to.window(self.driver.window_handles[-1]) 255 log.info(u'Click element %s Open a new window' % locator) 256 257 # old_handle = self.driver.current_window_handle 258 # self.get_element(locator).click() 259 # all_handles = self.driver.window_handles 260 # for handle in all_handles: 261 # if handle != old_handle: 262 # self.driver.switch_to.window(handle) 263 264 def open_new_window_by_element(self, element): 265 """ 266 Click the element to open a new window and switch the handle to the new window 267 :param element: Element object 268 """ 269 element.click() 270 self.driver.switch_to.window(self.driver.window_handles[-1]) 271 log.info(u'Click the element to open a new window') 272 273 def js(self, script): 274 """ 275 implement JavaScript 276 :param script:js sentence 277 """ 278 self.driver.execute_script(script) 279 log.info(u'implement JS sentence:%s' % script) 280 281 def scroll_element(self, locator): 282 """ 283 Drag the scroll bar to the target element 284 :param locator: Positioning method+Positioning expression combination string, such as'css,.username' 285 """ 286 script = "return arguments[0].scrollIntoView();" 287 element = self.get_element(locator) 288 self.driver.execute_script(script, element) 289 log.info(u'Scroll to element:%s' % locator) 290 291 def scroll_top(self): 292 """ 293 Scroll to top 294 """ 295 self.js("window.scrollTo(document.body.scrollHeight,0)") 296 log.info(u'Scroll to top') 297 298 def scroll_bottom(self): 299 """ 300 Scroll to bottom 301 """ 302 self.js("window.scrollTo(0,document.body.scrollHeight)") 303 log.info(u'Scroll to bottom') 304 305 def back(self): 306 """ 307 Page back 308 """ 309 self.driver.back() 310 log.info(u'Page back') 311 312 def forward(self): 313 """ 314 Page forward 315 """ 316 self.driver.forward() 317 log.info(u'Page forward') 318 319 def is_text_on_page(self, text): 320 """ 321 Return to page source code 322 :return: Page source code 323 """ 324 if text in self.driver.page_source: 325 log.info(u'Judge whether there is text on the page:%s' % text) 326 return True 327 else: 328 log.info(u'Judge that there is no text on the page:%s' % text) 329 return False 330 331 def refresh(self): 332 """ 333 Refresh page 334 """ 335 self.driver.refresh() 336 log.info(u'Refresh page') 337 338 def screenshot(self, info='-'): 339 """ 340 screenshot,Name: file name-Method name-notes 341 :param info: Screenshot description 342 """ 343 catalog_name = cf.get_value('screenshot_path') # Get screenshot folder location from global variable 344 if not os.path.exists(catalog_name): 345 os.makedirs(catalog_name) 346 class_object = inspect.getmembers(inspect.stack()[1][0])[-3][1]['self'] # Get the object of the test class 347 classname = str(class_object).split('.')[1].split(' ')[0] # Get test class name 348 testcase_name = inspect.stack()[1][3] # Get test method name 349 filepath = catalog_name + classname + "@" + testcase_name + info + ".png" 350 self.driver.get_screenshot_as_file(filepath) 351 log.info(u'Screenshot:%s.png' % info) 352 353 def close(self): 354 """ 355 Close current page 356 """ 357 self.driver.close() 358 self.driver.switch_to.window(self.driver.window_handles[0]) 359 log.info(u'Close current Tab') 360 361 def sleep(self, sec): 362 time.sleep(sec) 363 log.info(u'wait for%s second' % sec)
This framework supports all positioning methods of selenium. In order to improve the writing speed, the use method is improved. When defining elements, the method name and method value are a string separated by commas, such as:
- xpath positioning: i_keyword = 'xpath,//input[@id = "kw"]' # keyword input box
- id positioning: b_search = 'id,su' # search button
- Other positioning methods are the same as above and will not be exemplified one by one
When using the type() method in the above code, you enter text in the input box and type(i_keyword, "input content") when calling
Get is called in type()_ The element () method parses the entered positioning expression and waits for the element for a period of time. When the element appears, it will be operated immediately.
In addition, you can see that each basic operation is added to the log. The following figure is the log recorded in the report after the use case runs
search_page.py code implementation: Baidu's search page encapsulated in PO mode inherits the BasePage class above; In each page class, the expressions of each control are defined above, and various operations on the page are encapsulated as methods below. In this way, if control or operation methods are invoked in multiple use cases, updating maintenance in the future will only need to be changed in the page class, and all use cases will be updated.
1 # coding=utf-8 2 3 from page_object.base_page import BasePage 4 5 6 class SearchPage(BasePage): 7 def __init__(self, driver): 8 self.driver = driver 9 10 # i = input box, l = link, im = picture, t = text control, d=div, lab=label 11 # Contain_ Baidu Encyclopedia Search Results 12 l_baike = 'xpath,//a [(. = "Star Story Baidu Encyclopedia")] ' 13 14 # next page 15 b_next_page = 'link,next page>' 16 17 # previous page 18 b_up_page = 'xpath,//A [(. = "< previous")] ' 19 20 # Click on the Encyclopedia of search results 21 def click_result(self): 22 self.open_new_window_by_locator(self.l_baike) 23 self.sleep(3) 24 25 # Click next 26 def click_next_page(self): 27 self.click(self.b_next_page)
test_search.py code implementation: the test case of Baidu search page. Here I simply wrote two use cases. The first is to click the first search result after search to open it, and the second is to turn the page of search results. The specific operations in the use case are the operation methods encapsulated in the above page class.
1 # coding=utf-8 2 3 import sys 4 reload(sys) 5 sys.setdefaultencoding('utf8') 6 from page_object.home_page import HomePage 7 from page_object.search_page import SearchPage 8 import pytest 9 import config.config as cf 10 11 12 class TestSearch(): 13 """ 14 pytest: 15 Test files to test_start 16 Test class to Test Start, and cannot have__init__method 17 Test function to test_start 18 Assertion use assert 19 """ 20 driver = cf.get_value('driver') # Get driver from global variable 21 home_page = HomePage(driver) 22 search_page = SearchPage(driver) 23 24 def test_click_result(self): 25 """Search page-Click the first search result""" 26 try: 27 self.home_page.open_homepage() 28 self.home_page.input_keyword(u'Star Story') # Enter keywords 29 self.search_page.click_result() # Click Encyclopedia 30 assert self.home_page.is_text_on_page(u'Opening song of TV series "watching meteor shower together"') # The validation page opens 31 self.home_page.screenshot(u'Open search results') 32 self.search_page.close() # Close encyclopedia page 33 except Exception, e: 34 self.home_page.screenshot(u'Failed to open search results') 35 raise e 36 37 def test_click_next_page(self): 38 """Search page-Search Pagination """ 39 try: 40 self.search_page.click_next_page() # Click next 41 assert self.home_page.wait_element(self.search_page.b_up_page) # The previous page appears 42 self.search_page.scroll_element(self.search_page.b_up_page) # Scroll to the previous page 43 self.home_page.screenshot(u'Search Pagination ') 44 except Exception, e: 45 self.home_page.screenshot(u'Search page flipping failed') 46 raise e
conftest.py code implementation:
1.conftest.py is a file that pytest provides data and operation sharing. Its file name is fixed and cannot be modified.
2.conftest. The directory where the PY file is located must exist__ init__.py file.
3. Other files do not need to import conf test Py and pytest examples will be found automatically
4. All test files in the same directory will execute conf test before running Py file
5. Only in confitest Py adds the function of error reporting screenshots. If you need to perform some operations before and after the use case, you can write them here.
1 # coding=utf-8 2 3 import pytest 4 from py._xmlgen import html 5 import config.config as cf 6 import logging 7 8 log = logging.getLogger('szh.conftest') 9 10 11 @pytest.mark.hookwrapper 12 def pytest_runtest_makereport(item): 13 """When the test fails, an automatic screenshot is displayed to html In the report""" 14 pytest_html = item.config.pluginmanager.getplugin('html') 15 outcome = yield 16 report = outcome.get_result() 17 extra = getattr(report, 'extra', []) 18 19 if report.when == 'call' or report.when == "setup": 20 xfail = hasattr(report, 'wasxfail') 21 if (report.skipped and xfail) or (report.failed and not xfail): 22 file_name = report.nodeid.replace("::", "_") + ".png" 23 driver = cf.get_value('driver') # Get driver from global variable 24 screen_img = driver.get_screenshot_as_base64() 25 if file_name: 26 html = '<div><img src="data:image/png;base64,%s" alt="screenshot" style="width:600px;height:300px;" ' \ 27 'οnclick="window.open(this.src)" align="right"/></div>' % screen_img 28 extra.append(pytest_html.extras.html(html)) 29 report.extra = extra 30 report.description = str(item.function.__doc__)#.decode('utf-8', 'ignore') # If it is not decoded and converted to Unicode, an error will be reported when generating HTML 31 # report.nodeid = report.nodeid.encode("utf-8").decode("unicode_escape") 32 33 34 @pytest.mark.optionalhook 35 def pytest_html_results_table_header(cells): 36 cells.insert(1, html.th('Description')) 37 cells.pop() # Delete links in the last column of the report 38 39 40 @pytest.mark.optionalhook 41 def pytest_html_results_table_row(report, cells): 42 cells.insert(1, html.td(report.description)) 43 cells.pop() # Delete links in the last column of the report
run.py code implementation:
1.run.py is used to do some initialization, run tests, and test closure. See the comments in the code for details.
2. Put the initialization of the browser driver here and store the driver in the global variable, so that the browser can run all tests only once. If you want to open and close the browser once for each use case, you can put the method of defining the driver in conf test Py.
3.get_args() is encapsulated command-line parameter parsing, which is convenient to quickly define the running content when integrating Jenkins. At present, only one environment parameter -e is defined. You can set the test environment preview and online environment product. You can add more parameters as needed.
4. Calling method: Python run py -e product
5.main() encapsulates the command line execution mode of pytest, which can also be modified as needed.
1 # coding=utf-8 2 3 import pytest 4 import config.config as cf 5 from util.log import Logger 6 import argparse 7 from selenium import webdriver 8 from util.mail import send_mail 9 10 11 def get_args(): 12 """Command line parameter parsing""" 13 parser = argparse.ArgumentParser(description=u'Optional parameters:') 14 parser.add_argument('-e', '--environment', choices=['preview', 'product'], default='preview', help=u'testing environment preview,Online environment product') 15 args = parser.parse_args() 16 if args.environment in ('pre', 'preview'): 17 cf.set_value('environment', 'preview') 18 cf.set_value('site', 'http://www.baidu.com/') 19 elif args.environment in ('pro', 'product'): 20 cf.set_value('environment', 'preview') 21 cf.set_value('site', 'https://www.baidu.com/') 22 else: 23 print u"Please enter preview/product" 24 exit() 25 26 27 def set_driver(): 28 """set up driver""" 29 # Configuring Chrome Driver 30 chrome_options = webdriver.ChromeOptions() 31 chrome_options.add_argument('--start-maximized') # Browser maximization 32 chrome_options.add_argument('--disable-infobars') # Don't remind me that chrome is under the control of automation software 33 prefs = {'download.default_directory': cf.get_value('download_path')} 34 chrome_options.add_experimental_option('prefs', prefs) # Set default download path 35 # chrome_options.add_argument(r'--user-data-dir=D:\ChromeUserData') # Set the user folder to avoid login 36 driver = webdriver.Chrome('{}\\driver\\chromedriver.exe'.format(cf.get_value('root_path')), options=chrome_options) 37 cf.set_value('driver', driver) 38 39 40 def main(): 41 """function pytest Command start test""" 42 pytest.main(['-v', '-s', 'test_case/', '--html=report/report.html', '--self-contained-html']) 43 44 45 if __name__ == '__main__': 46 cf.init() # Initialize global variables 47 get_args() # Command line parameter parsing 48 log = Logger('szh') # Initialize log configuration 49 set_driver() # Initialize driver 50 main() # Run pytest test test set 51 cf.get_value('driver').quit() # Close selenium driver 52 53 # First put util Mail file send_ Fill in the user name and password in mail () correctly, and then enable the send mail function!!! 54 send_mail(['22459496@qq.com']) # Send report to mailbox
Finally, put a screenshot of the test report after running. I deliberately wrote a use case wrong. You can see that the report shows the specific error information and the screenshot of the page when the error occurs
All codes can be obtained from GitHub: https://github.com/songzhenhua/selenium_ui_auto