Easily implement a Python+Selenium automated testing framework

First of all, you have to know what is Selenium?

Selenium is a browser-based automated testing tool that provides a cross-platform, cross-browser end-to-end web automation solution. Selenium mainly includes three parts: Selenium IDE, Selenium WebDriver and Selenium Grid.

  • Selenium IDE: An extension of Firefox, it can record and play back, and export the recorded operations into test cases in multiple languages (such as java, python, etc.).
  • Selenium WebDriver: Provides the API required for Web automation, mainly used for browser control, page element selection and debugging. Different browsers require different WebDrivers.
  • Selenium Grid: Provides the ability to run selenium tests on different browsers on different machines.

Next, I will use the mind map directory structure to introduce the basic test framework, and write test cases for functional test cases. I hope it will be helpful to your study.

Design ideas

The framework uses python3 + selenium3 + PO + yaml + ddt + unittest and other technologies to write a basic test framework, which can meet the needs of daily testing work.

1. Use the Page Object mode to separate page positioning and business operations, separate test objects (element objects) and test scripts (use case scripts), build an object class for each page, and improve the maintainability of use cases;

2. Use yaml to manage page control element data and test case data. For example, when the element ID changes, you don’t need to modify the test code, you only need to modify it in the corresponding page element yaml file;

3. Sub-module management, independent of each other, assembled at any time, ready to use.

Layered Design of Test Framework

Encapsulate common operations and searches into basic classes, no matter what product it is, it can be reused directly

  • The business layer mainly encapsulates the object page class, one class is built for each page, and the business layer page inherits the base layer
  • The use case layer constructs the simulation execution test for the product page function
  • The framework layer provides basic components to support the entire process execution and function expansion, and provides the use case layer with element data of each page, use case test data, test report output, etc.

Test framework directory structure

The directory structure of the mind map is introduced as follows:

Writing a use case method

testinfo:
- id: test_login001
title: Login Test
info: open drawer home page
testcase:
- element_info: login-link-a
find_type: ID
operate_type: click
info: open the login dialog
- element_info: mobile
find_type: ID
operate_type: send_keys
info: enter the phone number
- element_info: mbpwd
find_type: ID
operate_type: send_keys
info: enter password
- element_info: //input[@class='keeplogin']
find_type: XPATH
operate_type: click
info: Click to cancel the automatic login radio box
- element_info: //span[text()='login']
find_type: XPATH
operate_type: click
info: click the login button
- element_info: userProNick
find_type: ID
operate_type: perform
info: mouseover account menu
- element_info: //a[@class='logout']
find_type: XPATH
operate_type: click
info: opt out
check:
- element_info: //div[@class='box-mobilelogin']
/div[1]/span
find_type: XPATH
info: check input mobile phone number or password, log in abnormal prompt
- element_info: userProNick
find_type: ID
info: successfully logged in
- element_info: reg-link-a
find_type: ID
info: Check if the logout is successful
login.yaml

For example, we want to add a login function test case:

First of all, just add a page object yaml file in the testyaml directory, and write it with reference to the login.yaml format. These files are provided to encapsulate page object classes to call and perform location recognition operations.

-
id: test_login001.1
detail : mobile phone number and password are empty to log in
screenshot : phone_pawd_empty
data:
phone: ""
password: ""
check:
- Mobile phone number cannot be empty
-
id: test_login001.2
detail : mobile phone number is empty to log in
screenshot : phone_empty
data:
phone: ""
password : aa
check:
- Mobile phone number cannot be empty
-
id: test_login001.3
detail : the password is empty to log in
screenshot : pawd_empty
data:
phone: 13511112222
password: ""
check:
- password can not be blank
-
id: test_login001.4
detail : Illegal phone number login
screenshot : phone_error
data:
phone: abc
password: aa
check:
- The format of the mobile phone number is wrong
-
id: test_login001.5
detail : phone number or password does not match
screenshot : pawd_error
data:
phone: 13511112222
password: aa
check:
- Wrong account password
-
id: test_login001.6
detail : The phone number and password are correct
screenshot : phone_pawd_success
data:
phone: 13865439800
password: ********
check:
- yingoja
login_data.yaml
 
login_data.yaml

Secondly, add a login_data.yaml file in the testdata directory to provide the test data for the login interface to pass parameters, and refer to the login_data.yaml file for the writing format.

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
__author__ = 'YinJia'
import os,sys
sys.path.append(os.path.dirname(os.path.dirname
(os. path. dirname(__file__))))
from config import setting
from selenium.webdriver.support.select import Select
from selenium.webdriver.common.action_chains
import ActionChains
from selenium.webdriver.common.by import By
from public.page_obj.base import Page
from time import sleep
from public.models.GetYaml import getyaml
testData = getyaml(setting.TEST_Element_YAML
 + '/' + 'login.yaml')
class login(Page):
"""
User login page
"""
url = '/'
dig_login_button_loc = (By.ID, testData.
get_elementinfo(0)) def dig_login(self):
"""
Home Login
:return:
"""
self. find_element(*self. dig_login_button_loc)
.click() sleep(1)
# Locator, locate the element object through the element attribute
# Mobile phone number input box
login_phone_loc = (By.ID,testData.
get_elementinfo(1)) # password input box
login_password_loc = (By.ID,testData.
get_elementinfo(2)) # cancel automatic login
keeplogin_button_loc = (By.XPATH,testData.
get_elementinfo(3)) # click login
login_user_loc = (By.XPATH,testData.
get_elementinfo(4)) # log out
login_exit_loc = (By.ID, testData.
get_elementinfo(5)) # opt out
login_exit_button_loc = (By.XPATH,testData.
get_elementinfo(6)) def login_phone(self, phone):
"""
log in with phone number
:param username:
:return:
"""
self. find_element(*self. login_phone_loc).
send_keys(phone) def login_password(self, password):
"""
login password
:param password:
:return:
"""
self. find_element(*self. login_password_loc).
send_keys(password) def keeplogin(self):
"""
Cancel radio automatic login
:return:
"""
self. find_element(*self. keeplogin_button_loc).
click() def login_button(self):
"""
login button
:return:
"""
self.find_element(*self.login_user_loc).click()
def login_exit(self):
"""
Exit system
:return:
"""
above = self. find_element(*self. login_exit_loc)
ActionChains(self. driver). move_to_element(above).
perform() sleep(2)
self. find_element(*self. login_exit_button_loc)
.click() def user_login(self, phone, password):
"""
Log entry
:param username: username
:param password: password
:return:
"""
self. open()
self. dig_login()
self. login_phone(phone)
self. login_password(password)
sleep(1)
self. keeplogin()
sleep(1)
self. login_button()
sleep(1)
phone_pawd_error_hint_loc = (By.XPATH,testData.
get_CheckElementinfo(0))
user_login_success_loc = (By.ID,testData.
get_CheckElementinfo(1))
exit_login_success_loc = (By.ID,testData.
get_CheckElementinfo(2))
# Phone number or password error prompt
def phone_pawd_error_hint(self):
return self.find_element(*self.phone_pawd_error_
hint_loc).text# login success username
def user_login_success_hint(self):
return self.find_element(*self.user_login_
success_loc).text # log out
def exit_login_success_hint(self):
return self.find_element(*self.exit_login_
success_loc).textloginPage.py

Then, add a loginPage.py file under the page_obj directory, which is used to encapsulate the login page object class and execute the login test process operation.

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
__author__ = 'YinJia'
import os,sys
sys.path.append(os.path.dirname(os.path.
dirname(__file__)))
import unittest,ddt,yaml
from config import setting
from public.models import myunit, screenshot
from public.page_obj.loginPage import login
from public.models.log import Log
try:
f =open(setting.TEST_DATA_YAML + '/' + 'login_data.yaml',encoding='utf-8')
testData = yaml. load(f)
except FileNotFoundError as file:
log = Log()
log.error("The file does not exist: {0}".format(file))
@ddt.ddt
class Demo_UI(myunit. MyTest):
"""Drawer new hot list login test"""
def user_login_verify(self, phone, password):
"""
User login
:param phone: phone number
:param password: password
:return:
"""
login(self.driver).user_login(phone,password)
def exit_login_check(self):
"""
sign out
:return:
"""
login(self. driver). login_exit()
@ddt.data(*testData)
def test_login(self, datayaml):
"""
login test
:param datayaml: load login_data login test data
:return:
"""
log = Log()
log.info("currently executing test case ID-> {0} ; test point-> {1}".format(datayaml['id'],datayaml['detail']))
# Call the login method
self.user_login_verify(datayaml['data']['phone'],
datayaml['data']['password'])
po = login(self. driver)
if datayaml['screenshot'] == 'phone_pawd_success':
log.info("Checkpoint -> {0}".format
(po. user_login_success_hint()))
self.assertEqual(po.user_login_success_hint(), datayaml['check'][0], "Successful login, the actual result returned is ->: {0}".format(po.user_login_success_hint()))
log.info("Successful login, the actual result returned is ->: {0}".format(po.user_login_success_hint()))
screenshot.insert_img(self.driver, datayaml
['screenshot'] + '.jpg')
log.info("-----> Start to execute exit process operation")
self. exit_login_check()
po_exit = login(self. driver)
log.info("Checkpoint -> found {0} element, indicating successful exit!".format(po_exit.exit_login_success_hint()))
self.assertEqual(po_exit.exit_login_success_hint(),
'Register',"Exit login, the actual result returned is ->: {0}".format(po_exit.exit_login_success_hint()))
log.info("Exit login, the actual result returned is ->: {0}".format(po_exit.exit_login_success_hint()))
else:
log.info("Checkpoint -> {0}".format(po.phone
_pawd_error_hint()))
self.assertEqual(po.phone_pawd_error_hint(),
datayaml['check'][0] , "Abnormal login, the actual result returned is ->: {0}".format(po.phone_pawd_error_hint()))
log.info("Abnormal login, the actual result returned is ->: {0}".format(po.phone_pawd_error_hint()))
screenshot.insert_img(self.driver,datayaml
['screenshot'] + '.jpg')
if __name__=='__main__':
unittest. main()
login_sta.py

Finally, create a test case file login_sta.py in the testcase directory, and use the ddt data driver to read the yaml test data file

To sum up, writing a use case method only needs to follow the above four steps to create -> write.

Execute the following main program, you can see the actual output results.

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
__author__ = 'YinJia' import os,sys
sys.path.append(os.path.dirname(__file__))
from config import setting
import unittest,time
from package.HTMLTestRunner import HTMLTestRunner
from public.models.newReport import new_report
from public.models.sendmail import send_mail
# Test report storage folder, if it does not exist, it will be created automatically
A report directory if not os.path.exists(setting.TEST_REPORT):os.makedirs
(setting.TEST_REPORT + '/' + "screenshot")
def add_case(test_path=setting.TEST_DIR):
"""Load all test cases"""
discover = unittest.defaultTestLoader.discover
(test_path, pattern='*_sta.py')
return discover
def run_case(all_case, result_path=setting.TEST_REPORT):
"""Execute all test cases"""
now = time.strftime("%Y-%m-%d %H_%M_%S")
filename = result_path + '/' + now + 'result.html'
fp = open(filename,'wb')
runner = HTMLTestRunner(stream=fp,title='
Drawer New Hot List UI Automation Test Report',
description='Environment: windows 7 browser: chrome',
tester='Jason')
runner. run(all_case)
fp. close()
report = new_report(setting.TEST_REPORT)
#Call the module to generate the latest report
send_mail(report) #call send mail module
if __name__ =="__main__":
cases = add_case()
run_case(cases)

Test result display

HTML report log

Click on the screenshot of the HTML report, and the screenshot will pop up

Test report passed log

Automatic screenshots are stored in the specified directory

Email test report

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledgePython entry skill treeWeb crawlerSelenium298966 people are studying systematically