Build a keyword-driven automated testing framework

Preface
In the last article, we have learned how the data-driven automated testing framework builds and drives tests! So in this article we will learn how keyword-driven testing drives automated testing to complete the entire testing process. Keyword-driven framework is a functional automation testing framework, which is also known as table-driven testing or action word-based testing. The basic job of the keyword driven framework is to split the test cases into four different parts. The first is the test step (Test Step), the second is the object in the test step (Test Object), the third is the action performed by the test object (Action), and the fourth is the data required by the test object (Test Data).

In fact, our idea of being keyword-driven is to separate coding from test cases and test steps, so that it is easier for people who cannot code to understand automation, so that manual testers can also write automatic scripts. (This does not mean that automated testers are not needed. A technical person is required for the construction of automated frameworks, automated code updates, structural adjustments, etc.) For teams testing small projects, there can be two manual testers and one Automation testers.

Project function
The function we will implement today is to test the login of 126 mailbox and send an email with an attachment after logging in.

Test address

126 NetEase free postage-your professional electronic post office

Project directory
Next, let’s take a look at how our project directory is designed. What is the function of each directory?

Framework construction

Next, let’s consider step by step how to build the entire project and how to write each py code file?

Main functional modules of the framework

1. Create a new util folder, and create a new ObjectMap.py file under this folder, which mainly implements the encapsulation of the page element search function

1 from selenium.webdriver.support.wait import WebDriverWait
 2 
 3
 4 def getElement(driver, by, locator):
 5 '''
 6 Find a single element
 7 :param driver:
 8 :param by:
 9 :param locator:
10 :return: element object
11 '''
12 try:
13 element = WebDriverWait(driver, 30).until(lambda x : x.find_element(by, locator))
14 except Exception as e:
15 raise e
16 else:
17 return element
18
19 def getElements(driver, by, locator):
20 '''
21 Get a set of elements
22 :param driver:
23 :param by:
24 :param locator:
25 :return: a set of element objects
26 '''
27 try:
28 elements = WebDriverWait(driver, 30).until(lambda x : x.find_element(by, locator))
29 except Exception as e:
30 raise e
31 else:
32 return elements
33
34
35 if __name__=="__main__":
36 from selenium import webdriver
37 import time
38
39 driver = webdriver.Firefox()
40 driver.get('https://mail.126.com')
41 time.sleep(5)
42 driver.switch_to.frame(getElement(driver, 'xpath', "//div[@id='loginDiv']/iframe"))
43 username = getElement(driver, 'xpath', "//input[@name='email']")
44 username.send_keys('linuxxiaochao')
45 driver.switch_to.default_content()
46 driver.quit()

2. Create a new WaitUntil.py file in the util folder, which mainly implements the encapsulation of the function of displaying waiting elements.

 1 from selenium.webdriver.common.by import By
 2 from selenium.webdriver.support.wait import WebDriverWait
 3 from selenium.webdriver.support import expected_conditions as EC
 4
 5 class WaitUnit(object):
 6 def __init__(self, driver):
 7 self.byDic = {
 8 'id': By.ID,
 9 'name': By.NAME,
10 'class_name': By.CLASS_NAME,
11 'xpath': By.XPATH,
12 'link_text': By.LINK_TEXT
13}
14 self.driver = driver
15 self.wait = WebDriverWait(self.driver, 50)
16
17 def presenceOfElementLocated(self, by, locator):
18 '''
19 Displays waiting for an element to appear in the dom, which may not be visible. There is an element object returned.
20 :param by:
21 :param locator:
22 :return:
twenty three         '''
24 try:
25 if by.lower() in self.byDic:
26 self.wait.until(EC.presence_of_element_located((self.byDic[by.lower()], locator)))
27 else:
28 raise TypeError('No positioning method found, please make sure the positioning method is correct')
29 except Exception as e:
30 raise e
31
32 def frameToBeAvailableAndSwtichToIt(self, by, locator):
33 '''
34 Check whether the frame exists, and switch to the frame if it exists.
35 :param by:
36 :param locator:
37 :return:
38 '''
39 try:
40 if by.lower() in self.byDic:
41 self.wait.until(EC.frame_to_be_available_and_switch_to_it((self.byDic[by.lower()], locator)))
42 else:
43 raise TypeError('No positioning method found, please make sure the positioning method is correct')
44 except Exception as e:
45 raise e
46 def visibiltyOfElementLocated(self, by, locator):
47 '''
48 Display waits for the page element to appear in the dom and be visible. If it exists, return the element object.
49 :param by:
50 :param locator:
51 :return:
52 '''
53 try:
54 if by.lower() in self.byDic:
55 self.wait.until(EC.visibility_of_element_located((self.byDic[by.lower()], locator)))
56 else:
57 raise TypeError('No positioning method found, please make sure the positioning method is correct')
58 except Exception as e:
59 raise e
60
61 if __name__=='__main__':
62 from selenium import webdriver
63 from util.ObjectMap import *
64 driver = webdriver.Firefox()
65 driver.get('https://mail.126.com')
66
67 wait = WaitUnit(driver)
68 wait.frameToBeAvailableAndSwtichToIt('xpath', "//div[@id='loginDiv']/iframe")
69 wait.visibiltyOfElementLocated('xpath', "//input[@name='email']")
70 uname = getElement(driver, 'xpath', "//input[@name='email']")
71 uname.send_keys('python')
72 driver.quit()

3. Create a new ClipboardUtil.py file to implement clipping operations (when we send emails, we need to add attachments, and this function is used to upload attachments)

 1 import win32clipboard as w
 2 import win32con
 3
 4 class Clipboard(object):
 5
 6 @staticmethod
 7 def getText():
 8         '''
 9 Get the contents of the clipboard
10 :return:
11 '''
12
13 try:
14 # Open clipboard
15 w.OpenClipboard()
16 # Read data
17 value = w.GetClipboardData(win32con.CF_TEXT)
18 # Close clipboard
19 w.CloseClipboard()
20 except Exception as e:
21 raise e
22 else:
23 return value
twenty four 
25 @staticmethod
26 def setText(value):
27 '''
28 Set clipboard content
29 :return:
30 '''
31 try:
32 w.OpenClipboard()# Open the clipboard
33 w.EmptyClipboard()# Clear the clipboard
34 w.SetClipboardData(win32con.CF_UNICODETEXT, value) # Set content
35 w.CloseClipboard() # Close
36 except Exception as e:
37 raise e
38
39 if __name__=='__main__':
40 from selenium import webdriver
41
42 value = 'python'
43 driver = webdriver.Firefox()
44 driver.get('http://www.baidu.com')
45 query = driver.find_element_by_id('kw')
46 Clipboard.setText(value)
47 clValue = Clipboard.getText()
48 query.send_keys(clValue.decode('utf-8'))

4. Create a new KeyBoardUtil.py file, which mainly implements simulated keyboard operations (cooperating with the above clipboard function, pasting the path of attachments, pressing Enter, etc.)

 1 import win32api
 2 import win32con
 3
 4 class KeyBoardKeys(object):
 5 '''
 6 simulated keyboard
 7 '''
 8 # Keyboard encoding
 9 vk_code ={
10 'enter':0x0D,
11 'tab' : 0x09,
12 'ctrl':0x11,
13 'v':0x56
14}
15 @staticmethod
16 def keyDown(keyName):
17 '''
18 Simulate key press
19 :param keyName:
20 :return:
twenty one         '''
22 try:
23 win32api.keybd_event(KeyBoardKeys.vk_code[keyName],0,0,0)
24 except Exception as e:
25 raise e
26 @staticmethod
27 def keyUp(keyName):
28 '''
29 release button
30 :param keyName:
31 :return:
32 '''
33 try:
34 win32api.keybd_event(KeyBoardKeys.vk_code[keyName],0,win32con.KEYEVENTF_KEYUP,0)
35 except Exception as e:
36 raise e
37 @staticmethod
38 def oneKey(key):
39 '''
40 Simulates being a button
41 :param key:
42 :return:
43 '''
44 try:
45 KeyBoardKeys.keyDown(key)
46 KeyBoardKeys.keyUp(key)
47 except Exception as e:
48 raise e
49
50 @staticmethod
51 def twoKeys(key1, key2):
52 '''
53 Simulate key combinations
54 :param key1:
55 :param key2:
56 :return:
57 '''
58 try:
59 KeyBoardKeys.keyDown(key1)
60 KeyBoardKeys.keyDown(key2)
61 KeyBoardKeys.keyUp(key1)
62 KeyBoardKeys.keyUp(key2)
63 except Exception as e:
64 raise e
65
66 if __name__=='__main__':
67 from selenium import webdriver
68
69 driver = webdriver.Firefox()
70 driver.get('http://www.baidu.com')
71 driver.find_element_by_id('kw').send_keys('python')
72 KeyBoardKeys.oneKey('enter')

5. Create a new DirAndTime.py file, which is mainly used to obtain the current time and generate a special path. It is mainly used to generate the path and image name for saving screenshots.

 1 from datetime import datetime, date
 2 from config.VarConfig import *
 3
 4 class DirAndTime(object):
 5 @staticmethod
 6 def getCurrentDate():
 7 '''
 8 Get current date
 9 :return:
10 '''
11 try:
12 currentDate = date.today()
13 except Exception as e:
14 raise e
15 else:
16 return str(currentDate)
17 @staticmethod
18 def getCurrentTime():
19 '''
20 Get the current time
21 :return:
twenty two         '''
23 try:
24 Time = datetime.now()
25 currentTime = Time.strftime('%H_%M_%S')
26 except Exception as e:
27 raise e
28 else:
29 return currentTime
30 @staticmethod
31 def CreatePicturePath():
32 '''
33 Create image storage path path
34 :return:
35 '''
36 try:
37
38 picturePath = os.path.join(exceptionPath, DirAndTime.getCurrentDate())
39 if not os.path.exists(picturePath):
40 os.makedirs(picturePath) # Generate multi-level directories
41 except Exception as e:
42 raise e
43 else:
44 return picturePath
45
46 if __name__=='__main__':
47 print(DirAndTime.getCurrentDate())
48 print(DirAndTime.getCurrentTime())
49 print(DirAndTime.CreatePicturePath())

6. Create a new ParseExcel.py to parse excel files

 1 from openpyxl import load_workbook
 2 from config.VarConfig import *
 3 from datetime import datetime, date
 4
 5 class ParseExcel(object):
 6 '''
 7 Parse the package of excel file
 8     '''
 9 def __init__(self):
10 #Load excel file into memory
11 self.wb = load_workbook(excelPath)
12
13 def getRowValue(self, sheetName, rawNo):
14 '''
15 Get the data of a certain row
16 :param sheetName:
17 :param rawNo:
18 :return: list
19 '''
20 sh = self.wb[sheetName]
21 rowValueList = []
22 for y in range(2, sh.max_column + 1):
23 value = sh.cell(rawNo,y).value
24 rowValueList.append(value)
25 return rowValueList
26 def getColumnValue(self, sheetName, colNo):
27 '''
28 Get data of a certain column
29 :param sheetName:
30 :param colNo:
31 :return: list
32 '''
33 sh = self.wb[sheetName]
34 colValueList = []
35 for x in range(2, sh.max_row + 1):
36 value = sh.cell(x, colNo).value
37 colValueList.append(value)
38 return colValueList
39
40 def getCellOfValue(self, sheetName, rowNo, colNo):
41 '''
42 Get the data of a certain cell
43 :param sheetName:
44 :param rowNo:
45 :param colNo:
46 :return: string
47 '''
48 sh = self.wb[sheetName]
49 value = sh.cell(rowNo, colNo).value
50 return value
51 def writeCell(self, sheetName, rowNo, colNo, value):
52 '''
53 Write data to a cell
54 :param rowNo: row number
55 :param colNo: column number
56 :param value:
57 :return: None
58 '''
59 sh = self.wb[sheetName]
60 sh.cell(rowNo, colNo).value = value
61 self.wb.save(excelPath)
62 def writeCurrentTime(self, sheetName, rowNo, colNo):
63 '''
64 Write the current time to a cell
65 :return:
66 '''
67 sh = self.wb[sheetName]
68 Time = datetime.now()
69 currentTime = Time.strftime('%Y:%m:%d %H:%M:%S')
70 sh.cell(rowNo, colNo).value = currentTime
71 self.wb.save(excelPath)
72
73 def writeTestResult(self, sheetName, rowNo, result, errorInfo = None, errorPic = None):
74 ParseExcel().writeCurrentTime(sheetName, rowNo, testStep_testRunTime)
75 ParseExcel().writeCell(sheetName, rowNo, testStep_testResult, result)
76 if errorInfo and errorInfo:
77 ParseExcel().writeCell(sheetName, rowNo, testStep_testErrorInfo, errorInfo)
78 ParseExcel().writeCell(sheetName, rowNo, testStep_testErrorPic, errorPic)
79 else:
80 ParseExcel().writeCell(sheetName, rowNo, testStep_testErrorInfo, '')
81 ParseExcel().writeCell(sheetName, rowNo, testStep_testErrorPic, '')
82 if __name__=='__main__':
83 p = ParseExcel()
84 print(p.getRowValue('126account',2))
85 print(p.getColumnValue('126account',3))
86 print(p.getCellOfValue('126account', 2, 3))

7. Create a new Log.py file to record code execution logs

 1 import logging
 2 import time
 3 from config.VarConfig import *
 4
 5 class Logger(object):
 6 '''
 7 encapsulated log module
 8     '''
 9 def __init__(self, logger, CmdLevel=logging.INFO, FileLevel=logging.INFO):
10 """
11
12 :param logger:
13 :param CmdLevel:
14 :param FileLevel:
15 """
16 try:
17 self.logger = logging.getLogger(logger)
18 self.logger.setLevel(logging.DEBUG) # Set the default level of log output
19 # Log output format
20 fmt = logging.Formatter('%(asctime)s - %(filename)s:[%(lineno)s] - [%(levelname)s] - %(message)s')
21 # Log file name
22 # self.LogFileName = os.path.join(conf.log_path, "{0}.log.txt".format(time.strftime("%Y-%m-%d")))# %H_%M_%S
23 currTime = time.strftime("%Y-%m-%d")
24 self.LogFileName = logPath + currTime + '.txt'
25 # Set console output
26 # sh = logging.StreamHandler()
27 # sh.setFormatter(fmt)
28 # sh.setLevel(CmdLevel)# Log level
29
30 # Set file output
31 fh = logging.FileHandler(self.LogFileName)
32 fh.setFormatter(fmt)
33 fh.setLevel(FileLevel)# Log level
34
35 # self.logger.addHandler(sh)
36 self.logger.addHandler(fh)
37 except Exception as e:
38 raise e
39
40 if __name__ == '__main__':
41 logger = Logger("fox",CmdLevel=logging.DEBUG, FileLevel=logging.DEBUG)
42 logger.logger.debug("debug")
43 logger.logger.log(logging.ERROR,'%(module)s %(info)s',{'module':'log log','info':'error\ '}) #ERROR,log error
Business operation function module

Create a new action folder, which mainly stores various operations on the page, such as click operations, input operations, etc. 1. Create a new PageAction.py file under the folder

  1 from util.ObjectMap import *
  2 from util.ClipboardUtil import Clipboard
  3 from util.KeyBoardUtil import KeyBoardKeys
  4 from util.WaitUntil import WaitUnit
  5 from util.DirAndTime import *
  6 from selenium import webdriver
  7
  8 driver=None
  9 waitUtil = None
 10 # Open browser
 11 def openBrowser(browser):
 12 global driver, waitUtil
 13 try:
 14 if browser.lower() =='ie':
 15 driver = webdriver.Ie(executable_path=iePath)
 16 elif browser.lower() == 'chrome':
 17 driver = webdriver.Chrome(executable_path=chromePath)
 18 else:
 19 # driver = webdriver.Firefox(executable_path=fireFox)
 20 driver = webdriver.Firefox()
 21 except Exception as e:
 22 raise e
 23 else:
 24 waitUtil = WaitUnit(driver) # After driver is created, create wait class instance object
 25
 26 # Maximize browser window
 27 def maximize_browser():
 28 try:
 29 driver.maximize_window()
 30 except Exception as e:
 31 raise e
 32 # Load URL
 33 def loadUrl(url):
 34 try:
 35 driver.get(url)
 36 except Exception as e:
 37 raise e
 38
 39 # Forced wait
 40 def sleep(sleepSeconds):
 41 try:
 42 import time
 43 time.sleep(sleepSeconds)
 44 except Exception as e:
 45 raise e
 46 # Clear the content of the input box
 47 def clear(by, locator):
 48 try:
 49 getElement(driver, by, locator).clear()
 50 except Exception as e:
 51 raise e
 52 # Enter content in the input box
 53 def inputValue(by, locator, value):
 54 try:
 55 element = getElement(driver, by, locator)
 56 #element.click()
 57 element.send_keys(value)
 58 except Exception as e:
 59 raise e
 60 # Click operation
 61 def clickBtn(by, locator):
 62 try:
 63 getElement(driver, by, locator).click()
 64 except Exception as e:
 65 raise e
 66 # Assert the title of the page
 67 def assertTitle(titleStr):
 68 try:
 69 assert titleStr in driver.title, "%s not found in title!" % titleStr
 70 except AssertionError as e:
 71 raise AssertionError(e)
 72 except Exception as e:
 73 raise e
 74
 75 # Assert whether the target string is included in the page source code
 76 def assert_string_in_page_source(assertString):
 77 try:
 78 assert assertString in driver.page_source, "%s not found in page source!" % assertString
 79 except AssertionError as e:
 80 raise AssertionError(e)
 81 except Exception as e:
 82 raise e
 83
 84 # Get the title of the current page
 85 def getTitle():
 86 try:
 87 return driver.title
 88 except Exception as e:
 89 raise e
 90
 91 # Get page source code
 92 def getPageSource():
 93 try:
 94 return driver.page_source
 95 except Exception as e:
 96 raise e
 97 # Switch to frame
 98 def switchToFrame(by, locator):
 99 try:
100 driver.switch_to.frame(getElement(driver, by, locator))
101 except Exception as e:
102 raise e
103
104 # Jump to the default frame
105 def switchToDefault():
106 try:
107 driver.switch_to.default_content()
108 except Exception as e:
109 raise e
110
111 # Simulate ctrl + v key
112 def ctrlV(value):
113 try:
114 Clipboard.setText(value)
115 sleep(2)
116 KeyBoardKeys.twoKeys('ctrl', 'v')
117 except Exception as e:
118 raise e
119
120 # Simulate tab key
121 def tabKey():
122 try:
123 KeyBoardKeys.oneKey('tab')
124 except Exception as e:
125 raise e
126
127 # Simulate enter key
128 def enterKey():
129 try:
130 KeyBoardKeys.oneKey('enter')
131 except Exception as e:
132 raise e
133
134 # Screenshot
135 def saveScreenShot():
136 pictureName = DirAndTime.CreatePicturePath() + '\' + DirAndTime.getCurrentTime() + '.png'
137 try:
138 driver.get_screenshot_as_file(pictureName)
139 except Exception as e:
140 raise e
141 else:
142 return pictureName
143
144 def waitPresenceOfElementLocated(by, locator):
145 '''
146 Display waits for the page element to appear in the DOM, but it may not be visible
147 :param by:
148 :param locator:
149 :return:
150 '''
151 waitUtil.presenceOfElementLocated(by, locator)
152
153 def waitFrameToBeAvailableAndSwitchToIt(by, locator):
154 '''
155 Check whether the frame exists. If it exists, switch to the frame.
156 :param by:
157 :param locator:
158 :return:
159 '''
160 waitUtil.frameToBeAvailableAndSwtichToIt(by, locator)
161
162 def waitVisibiltyOfElementLocated(by, locator):
163 '''
164 Display waits for the page element to appear in the DOM and be visible
165 :param by:
166 :param locator:
167 :return:
168 '''
169 waitUtil.visibiltyOfElementLocated(by, locator)
170
171 # Close browser
172 def quitBroswer():
173 try:
174 driver.quit()
175 except Exception as e:
176 raise e
177 if __name__=='__main__':
178 openBrowser('firefox')
179 loadUrl('http://www.baidu.com')
180 # inputValue('id', 'kw','python')
181 # clear('id', 'kw')
182 # inputValue('id', 'kw', 'python')
183 # clickBtn('id', 'su')
184 #sleep(3)
185 # title = getTitle()
186 #print(title)
187 # assertTitle('python')
188 # assert_string_in_page_source('python')
189 ctrlV('python')
Project data file design

Since we want to implement keyword-driven testing, we will undoubtedly control the execution of the code through keyword data files.

Create a new testData folder and create a new 126mailSend.xlsx file. The file content includes 3 sheet pages, namely test cases, login, and sending emails.

Test case page

Login page

Send email Page

Note: The keywords in the table need to be consistent with the method names in PageAction.py

Project configuration module

Create a new config directory and create a VarConfig.py file to record the global directory and excel file partial information.

 1 # Store global variables
 2 import os
 3
 4 # Project root directory
 5 projectPath = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 6 # Screenshot directory
 7 exceptionPath = projectPath + r'\exceptionpictures'
 8 
 9 # The driver storage path needs to be modified according to the driver of your own computer.
10 iePath = ''
11 chromePath = ''
12 fireFox = ''
13
14 # Excel file storage path
15 excelPath = projectPath + r'\testData\126mailSend.xlsx'
16 # loh file storage path
17 logPath = projectPath + '\\log\'
18 # Column number corresponding to the test case part column
19 testCase_testCaseName = 2
20 testCase_testStepName = 4
21 testCase_testIsExecute = 5
22 testCase_testRunEndTime = 6
23 testCase_testResult = 7
twenty four 
25 # Column number corresponding to the use case step
26 testStep_testNum = 1
27 testStep_testStepDescribe = 2
28 testStep_keyWord = 3
29 testStep_elementBy = 4
30 testStep_elementLocator = 5
31 testStep_operateValue = 6
32 testStep_testRunTime = 7
33 testStep_testResult = 8
34 testStep_testErrorInfo = 9
35 testStep_testErrorPic = 10
36
37
38 if __name__=='__main__':
39
40 print(projectPath)
41 print(exceptionPath)
Test case writing

All the preliminary preparations have been completed, now we start writing test cases

Create a new testCases folder and create a new Test126SendMailWithAttachment.py to write the use case

 1 from util.ParseExcel import ParseExcel
 2 from config.VarConfig import *
 3 from action.PageAction import *
 4 import traceback
 5 from util.log import Logger
 6 import logging
 7
 8 log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
 9 p = ParseExcel()
10 sheetName = p.wb.sheetnames# Get all sheet names in excel
11
12 def Test126MailSendWithAtt():
13 try:
14 testCasePassNum = 0
15
16 requiredCase = 0
17 isExecuteColumnValues = p.getColumnValue(sheetName[0], testCase_testIsExecute)
18 # print(columnValues)
19 for index, value in enumerate(isExecuteColumnValues):
20 # print(index, value)
21 # Get the corresponding step sheet name
22 stepSheetName = p.getCellOfValue(sheetName[0],index + 2, testCase_testStepName)
23 # print(stepSheetName)
24 if value.strip().lower() == 'y':
25 requiredCase + = 1
26 testStepPassNum = 0
27 print('Start executing test case"{}"'.format(stepSheetName))
28 log.logger.info('Start executing test case"{}"'.format(stepSheetName))
29 # If the use case is marked for execution y, switch to the corresponding sheet page
30 # Get the total number of steps, keywords, positioning methods, positioning expressions, and operation values in the corresponding sheet
31 # Total number of steps
32 values = p.getColumnValue(stepSheetName, testStep_testNum) #The first column of data
33 stepNum = len(values)
34 print(stepNum)
35 for step in range(2, stepNum + 2):
36 rawValue = p.getRowValue(stepSheetName, step)
37 #Execution step name
38 stepName = rawValue[testStep_testStepDescribe -2]
39 # Keywords
40 keyWord = rawValue[testStep_keyWord - 2]
41 # Positioning method
42 by = rawValue[testStep_elementBy - 2]
43 # Positioning expression
44 locator = rawValue[testStep_elementLocator - 2]
45 # Operation value
46 operateValue = rawValue[testStep_operateValue - 2]
47
48 if keyWord and by and locator and operateValue:
49 func = keyWord + '(' + '"' + by + '"' + ',' + '"' + locator + '"' + \ ',' + '"' + operateValue + '"' + ')'
50 elif keyWord and by and locator and operateValue is None:
51 func = keyWord + '(' + '"' + by + '"' + ',' + '"' + locator + '"' + \ ')'
52
53 elif keyWord and operateValue and type(operateValue) == str and by is None and locator is None:
54 func = keyWord + '(' + '"' + operateValue + '"' + ')'
55
56 elif keyWord and operateValue and type(operateValue) == int and by is None and locator is None:
57 func = keyWord + '(' + str(operateValue) + ')'
58
59 else:
60 func = keyWord + '(' + ')'
61
62 try:
63 # Execute test steps
64 eval(func)
65 exceptException:
66 # Screenshot
67 picPath = saveScreenShot()
68 # Write back test results
69 errorInfo = traceback.format_exc()
70 p.writeTestResult(stepSheetName, step, 'Failed', errorInfo, picPath)
71 print('Step"{}"Execution failed'.format(stepName))
72 log.logger.info('Step"{}"Execution failed'.format(stepName))
73 raise
74 else:
75 print('Step"{}" is executed through'.format(stepName))
76 log.logger.info('Step"{}" is executed through'.format(stepName))
77 # Mark the test step as pass
78 p.writeTestResult(stepSheetName, step, 'Pass')
79 testStepPassNum + = 1
80 # print('Number of steps through the use case:',testStepPassNum)
81 if testStepPassNum == stepNum:
82 # Mark the execution result of the test case sheet page as pass
83 p.writeCell(sheetName[0], index + 2, testCase_testResult, 'Pass')
84 testCasePassNum + = 1
85 else:
86 p.writeCell(sheetName[0], index + 2, testCase_testResult, 'Failed')
87 print('Total {} use cases, {} need to be executed, this execution passes {}'.format(len(isExecuteColumnValues), requiredCase, testCasePassNum))
88 log.logger.info('Total {} use cases, {} need to be executed, this execution passes {}'.format(len(isExecuteColumnValues), requiredCase, testCasePassNum))
89 except Exception as e:
90 print(traceback.format_exc(e))
91 log.logger.info(traceback.format_exc(e))
92
93 if __name__=='__main__':
94 Test126MailSendWithAtt()
Loading use cases

Create a new RunTest.py directly in the main directory of the project, and use the test case to run the test case

1 if __name__=='__main__':
2 from testCases.Test126SendMailWithAttachment import Test126MailSendWithAtt
3 Test126MailSendWithAtt()

Project summary
1. Use external test data files, use Excel to manage the collection of test cases and all test steps of each test case, and complete the maintenance of test cases in one file.

2. The test results of each test case are viewed and counted in a file

3. By defining keywords, positioning methods of operation elements, positioning expressions and operation values, the execution of each test case step can be realized, and the needs of automated testing can be realized more flexibly.

4. Realize the separation of positioning expressions and test code, and realize positioning expressions to be maintained directly in the test data file.

5. The framework provides a log function to facilitate debugging and monitoring the execution of automated test programs.

6. Based on the keyword testing framework, even testers who do not understand development technology can implement automated testing, which facilitates the promotion and use of automated testing technology throughout the entire testing team and lowers the technical threshold for automated testing implementation.

7. Based on the keyword method, any keyword can be expanded to meet the automated testing needs of more complex projects.

Run the framework
1. The operating environment requires the installation of python3.x + selenium2.x; third-party modules openpyxl, pypiwin32,
win32api, win32con
2. The chrome/firefox/ie browser and corresponding version driver have been configured locally.
3. Need to modify the corresponding user name and password in the Excel file
4. Directly run the RunTest.py file to execute the entire framework
Finally, I would like to thank everyone who read my article carefully. Reciprocity is always necessary. Although it is not a very valuable thing, if you can use it, you can just take it away:

How to obtain documents

Join my software testing exchange group: 632880530 to get it for free~ (Academic exchanges with fellow leaders, and there will be live broadcasts every night to share technical knowledge points)

This document should be the most comprehensive and complete preparation warehouse for friends who want to engage in [software testing]. This warehouse has also accompanied me through the most difficult journey. I hope it can also help you!

All of the above can be shared. You only need to search the vx official account: Programmer Hugo to get it for free