You can't imagine how easy it is to implement a Python+Selenium automated testing framework!

First of all, what do you need to know about Selenium?

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

  • Selenium IDE: an extension of Firefox, which can record and play back, and export the recorded operations into test cases in various 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 need 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, hoping to help your learning.

Design thinking

The framework is composed of python3 + selenium 3 + Po + yaml + DDT + unittest and other technologies, which can meet the needs of daily test work.

  1. Use Page Object mode to separate page positioning and business operation, separate test object (element object) and test script (use case script), build an object class for a page, and improve the maintainability of use case;

  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 just need to modify it in the corresponding page element yaml file;

  3. Sub module management, mutual influence, assembly at any time, that is, take it and use it.

Layered design of test framework

 

Encapsulate common operations and lookups into basic classes. No matter what product it is, it can be reused directly

  • The business layer is mainly to encapsulate the object page class, build a class for a page, and the business layer page inherits the basic layer

  • Use case layer constructs simulation execution test for product page function

  • The framework layer provides basic components, supports the whole process execution and function expansion, and provides element data, use case test data, test report output, etc. of each page to the use case layer

Test framework directory structure

 

The structure of mind map directory is as follows:

 

Write use case method

If for software testing, interface testing, automation testing, interview experience exchange. Interested can be concerned about our code, the official account will be issued periodically, free information links, all these data are collected and sorted out from various technical websites. If you have good learning materials, you can chat with me privately, I will share the source with you after sharing the source.


testinfo:
- id: test_login001
title: Login test
info: Open the drawer front page
testcase:
- element_info: login-link-a
find_type: ID
operate_type: click
info: Open login dialog
- element_info: mobile
find_type: ID
operate_type: send_keys
info: Enter phone number
- element_info: mbpwd
find_type: ID
operate_type: send_keys
info: Input password
- element_info: //input[@class='keeplogin']
find_type: XPATH
operate_type: click
info: Click the cancel auto 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: Mouse over 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 and input the mobile number or password, and the login exception prompt
- element_info: userProNick
find_type: ID
info: Successful login
- element_info: reg-link-a
find_type: ID
info: Check whether the logout is successful
login.yaml

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

First of all, you only need to add a yaml file of page object in testyaml directory, and write it in login.yaml format. These files are provided to encapsulate page object class calls and perform location recognition operations.


-
id: test_login001.1
detail : Mobile number and password are empty login
screenshot : phone_pawd_empty
data:
phone: ""
password: ""
check :
- Mobile number cannot be empty
-
id: test_login001.2
detail : Mobile number is empty login
screenshot : phone_empty
data :
phone: ""
password : aa
check :
- Mobile number cannot be empty
-
id: test_login001.3
detail : Password is empty login
screenshot : pawd_empty
data :
phone : 13511112222
password: ""
check :
- Password cannot be empty
-
id: test_login001.4
detail : Illegal mobile number login
screenshot : phone_error
data :
phone : abc
password: aa
check :
- Wrong mobile number format
-
id: test_login001.5
detail : Phone number or password mismatch
screenshot : pawd_error
data :
phone : 13511112222
password: aa
check :
- Account password error
-
id: test_login001.6
detail : 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 new 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 page login
:return:
"""
self.find_element(*self.dig_login_button_loc)
.click() sleep(1)
# Locators, locating element objects through element attributes
# 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)) # Logout
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):
"""
//Login mobile 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 Auto 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):
"""
//Logon entrance
:param username: User name
: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 user name
def user_login_success_hint(self):
return self.find_element(*self.user_login_
success_loc).text # Logout
def exit_login_success_hint(self):
return self.find_element(*self.exit_login_
success_loc).textloginPage.py

Then, a loginPage.py file is added in the page obj directory to encapsulate the login page object class and perform the login test process.


#!/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("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: Cell-phone number
:param password: Password
:return:
"""
login(self.driver).user_login(phone,password)
def exit_login_check(self):
"""
//Logout
:return:
"""
login(self.driver).login_exit()
@ddt.data(*testData)
def test_login(self,datayaml):
"""
//Login test
:param datayaml: Load login_data Log in test data
:return:
"""
log = Log()
log.info("Current execution test case ID-> {0} ; Test point-> {1}".format(datayaml['id'],datayaml['detail']))
# Call 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], "Log in successfully. The actual result is->: {0}".format(po.user_login_success_hint()))
log.info("Log in successfully. The actual result is->: {0}".format(po.user_login_success_hint()))
screenshot.insert_img(self.driver, datayaml
['screenshot'] + '.jpg')
log.info("-----> Start exit process operation")
self.exit_login_check()
po_exit = login(self.driver)
log.info("Checkpoint-> find{0}element,Exit succeeded!".format(po_exit.exit_login_success_hint()))
self.assertEqual(po_exit.exit_login_success_hint(),
'register',"Log out and return the actual result->: {0}".format(po_exit.exit_login_success_hint()))
log.info("Log out and the actual result 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, return the actual result is->: {0}".format(po.phone_pawd_error_hint()))
log.info("Abnormal login, return the actual result 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 the 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, to write use case method, you only need to create - > write according to the above four steps.

Execute the following main program to see the actual output.


#!/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='
//New hot list of drawersUIAutomated test report',
description='Environmental Science: 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 results display

HTML report log

 

Click the screenshot of HTML report to pop up the screenshot

 

Log of test report passing

 

Automatic screenshot to store the specified directory

 

Mail test report

 

Tags: Programming Selenium Mobile Python Firefox

Posted on Thu, 05 Mar 2020 00:06:53 -0800 by daphreeek