UI自动化测试项目应用

场景:登陆系统,添加端口组,编辑端口组,删除端口组

目录结构:

common用于存放公共方法、driver用于存放浏览器驱动、pages用于存放各个页面元素定位及封装操作、report用于存放测试报告、testcases用于存放各个测试用例、test_suite.py文件用于批量执行测试用例并生成测试报告

一、common\base_page.py创建基础页面类,封装了一些公共常用页面元素定位和操作方法,其他页面都继承该类,完整代码如下:

from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


class BasePage(object):
"""
BasePage封装所有页面都公用的方法,例如driver, url ,FindElement等
"""

# 初始化driver、url、pagetitle等
# 实例化BasePage类时,最先执行的就是__init__方法,该方法的入参,其实就是BasePage类的入参。
# __init__方法不能有返回值,只能返回None
# self只实例本身,相较于类Page而言。
def __init__(self, selenium_driver, base_url):
self.driver = selenium_driver
self.base_url = base_url

# 打开页面,并校验页面链接是否加载正确
# 以单下划线_开头的方法,在使用import *时,该方法不会被导入,保证该方法为类私有的。
def _open(self, url):
# 使用get打开访问链接地址
self.driver.get(url)
self.driver.maximize_window()

# 定义open方法,调用_open()进行打开链接
def open(self):
self._open(self.base_url)

# 重写元素定位方法
def find_element(self, *loc):
# return self.driver.find_element(*loc)
try:
WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located(loc))
return self.driver.find_element(*loc)
except:
print (u"%s 页面中未能找到 %s 元素" % (self, loc))

# 重写switch_frame方法
def switch_frame(self, loc):
return self.driver.switch_to_frame(loc)

# 定义script方法,用于执行js脚本,范围执行结果
def script(self, src):
self.driver.execute_script(src)

# 重写定义send_keys方法
def send_keys(self, loc, vaule, clear_first=True, click_first=True):
try:
loc = getattr(self, "_%s" % loc) # getattr相当于实现self.loc
if click_first:
self.find_element(*loc).click()
if clear_first:
self.find_element(*loc).clear()
self.find_element(*loc).send_keys(vaule)
except AttributeError:
print (u"%s 页面中未能找到 %s 元素" % (self, loc))

二、pages\login_page.py用于定位登陆页面元素,封装元素操作方法,完整代码如下:
from common.base_page import BasePage
from selenium.webdriver.common.by import By

# 继承BasePage类
class LoginPage(BasePage):
# 定位器,通过元素属性定位元素对象
username_loc = (By.XPATH, '//*[@id="page-login"]/div[2]/form/div[1]/div/div/input')
password_loc = (By.XPATH, '//*[@id="page-login"]/div[2]/form/div[2]/div/div/input')
code_loc = (By.XPATH, '//*[@id="page-login"]/div[2]/form/div[3]/div/div/input')
submit_loc = (By.CSS_SELECTOR, '.login-text')
userid_loc = (By.ID, "spnUid")

# 操作
# 通过继承覆盖(Overriding)方法:如果子类和父类的方法名相同,优先用子类自己的方法。
# 打开网页
def open(self):
# 调用page中的_open打开连接
self._open(self.base_url)

# 输入用户名
def input_username(self, username):
self.find_element(*self.username_loc).send_keys(username)

# 输入密码
def input_password(self, password):
self.find_element(*self.password_loc).send_keys(password)

# 输入验证码
def input_code(self, code):
self.find_element(*self.code_loc).send_keys(code)

# 点击登录
def click_submit(self):
self.find_element(*self.submit_loc).click()
三、common\common_login.py用于封装公共登陆方法,其他测试用例有登陆操作直接调用该类中的方法即可完成登陆流程,完整代码如下:
import unittest
import time
from pages.login_page import LoginPage
from selenium import webdriver


class CommonLogin():
driver = webdriver.Chrome(executable_path=r".\driver\chromedriver.exe")
driver.implicitly_wait(30)
url = "http://*.*.*.*:*/login"
username = "*"
password = "*"
code = "*"
# 声明LoginPage类对象
login_page = LoginPage(driver, url)
# 打开页面
login_page.open()
time.sleep(2)
# 输入用户名
login_page.input_username(username)
# 输入密码
login_page.input_password(password)
# 输入验证码
login_page.input_code(code)
# 点击登录按钮
login_page.click_submit()

if __name__ == "__main__":
unittest.main()
四、pages\all_menu_user.py用于定位菜单栏元素及封装元素操作方法,完整代码如下:
from common.base_page import BasePage
from selenium.webdriver.common.by import By

# 继承BasePage类
class AllMenu(BasePage):
# 定位器,通过元素属性定位元素对象
rule_management_loc = (By.XPATH, '//*[@id="page-home"]/section/section/aside/div/div[1]/div/ul/li[8]/div')
port_management_loc = (By.XPATH, '//*[@id="page-home"]/section/section/aside/div/div[1]/div/ul/li[8]/ul/li[2]')


# 操作
# 点击规则管理
def click_rule_management(self):
self.find_element(*self.rule_management_loc).click()

# 点击端口管理
def click_port_management(self):
self.find_element(*self.port_management_loc).click()
五、pages\port_management_page.py用于定位端口管理界面元素及封装元素操作方法,完整代码如下:
from common.base_page import BasePage
from selenium.webdriver.common.by import By

# 继承BasePage类
class PortManagementPage(BasePage):
# 定位器,通过元素属性定位元素对象
create_button_loc = (By.XPATH, '//*[@id="page-home"]/section/section/main/div[2]/div[1]/div/div/button')
edit_button_loc = (By.XPATH, '//*[@id="page-home"]/section/section/main/div[2]/div[2]/div[1]/div[3]/table/tbody/tr[1]/td[8]/div/button[1]')
delete_button_loc = (By.XPATH, '//*[@id="page-home"]/section/section/main/div[2]/div[2]/div[1]/div[3]/table/tbody/tr[1]/td[8]/div/button[2]')
confirm_button_loc = (By.XPATH, '/html/body/div[2]/div/div[3]/button[2]')
text_loc = (By.CLASS_NAME, 'el-message__content')

# 操作
# 通过继承覆盖(Overriding)方法:如果子类和父类的方法名相同,优先用子类自己的方法。

# 点击新建按钮
def click_create_button(self):
self.find_element(*self.create_button_loc).click()

# 点击编辑按钮
def click_edit_button(self):
self.find_element(*self.edit_button_loc).click()

# 点击删除按钮
def click_delete_button(self):
self.find_element(*self.delete_button_loc).click()

# 点击弹出框确定按钮
def click_confirm_button(self):
self.find_element(*self.confirm_button_loc).click()

# 获取提示信息
def get_text(self):
return self.find_element(*self.text_loc).text
六、pages\create_edit_port_page.py用于定位创建/编辑端口组界面元素及封装元素操作方法,完整代码如下:
from common.base_page import BasePage
from selenium.webdriver.common.by import By

# 继承BasePage类
class CreateEditPortPage(BasePage):
# 定位器,通过元素属性定位元素对象
port_name_loc = (By.CSS_SELECTOR, 'body > div.el-dialog__wrapper > div > div.el-dialog__body > form > div:nth-child(1) > div > div > input')
port_content_loc = (By.CLASS_NAME, 'el-textarea__inner')
confirm_button_loc = (By.CSS_SELECTOR, 'body > div.el-dialog__wrapper > div > div.el-dialog__footer > div > button.el-button.el-button--primary')

# 操作
# 通过继承覆盖(Overriding)方法:如果子类和父类的方法名相同,优先用子类自己的方法。

# 输入端口组名
def input_port_name(self, portname):
self.find_element(*self.port_name_loc).send_keys(portname)

# 输入端口组内容
def input_port_content(self, portcontent):
self.find_element(*self.port_content_loc).send_keys(portcontent)

# 点击确定按钮
def click_confirm_button(self):
self.find_element(*self.confirm_button_loc).click()
七、common\search_mysql.py用于封装查找数据库公共方法,完整代码如下:
import pymysql

class SearchMysql():
def search_mysql(self, sql):
self.host = "*.*.*.*"
self.user = "*"
self.password = "*"
self.database = "*"
self.conn = pymysql.connect(self.host, self.user, self.password, self.database, charset="utf8")
self.cur = self.conn.cursor()
self.sql1 = sql
try:
self.cur.execute(self.sql1)
sth = self.cur.fetchall()[0][0]
except:
sth = '数据库未找到该数据!'
return sth
八、testcases\zjtest_port.py用于编写创建端口组、编辑端口组、删除端口组用例,完整代码如下:
import unittest
import time
from common.common_login import CommonLogin
from pages._7rule._2port.create_edit_port_page import CreateEditPortPage
from pages._7rule._2port.port_management_page import PortManagementPage
from pages.all_menu_user import AllMenu
from common.search_mysql import SearchMysql
class TestPort(unittest.TestCase):

@classmethod
def setUpClass(cls):
cls.common_login = CommonLogin()
cls.driver = cls.common_login.driver
cls.url = cls.common_login.url

cls.create_portname = "创建端口组"
cls.create_portcontent = "80"
cls.search_create_portname = "select name from gh_ports where name = " + '"'+ cls.create_portname + '"' +" and user_id = 83"

cls.edit_portname = "编辑端口组"
cls.edit_portname1 = "创建端口组编辑端口组"
cls.edit_portcontent = ",8080"
cls.search_edit_portname = "select name from gh_ports where name = " + '"'+ cls.edit_portname1 + '"' + " and user_id = 83"

# 声明AllMenu、PortManagementPage、CreateEditPortPage、SearchMysql类对象
cls.port_management_page = PortManagementPage(cls.driver, cls.url)
cls.create_edit_port_page = CreateEditPortPage(cls.driver, cls.url)
cls.all_menu = AllMenu(cls.driver, cls.url)
cls.search_mysql = SearchMysql()

# 新建端口组
def test_1create_port(self):
time.sleep(3)
# 点击规则管理模块
self.all_menu.click_rule_management()
# 点击端口组管理模板模块
self.all_menu.click_port_management()
time.sleep(3)
# 点击新建端口组按钮
self.port_management_page.click_create_button()
time.sleep(3)
# 输入端口组名
self.create_edit_port_page.input_port_name(self.create_portname)
# 输入端口组内容
self.create_edit_port_page.input_port_content(self.create_portcontent)
# 点击确定按钮
self.create_edit_port_page.click_confirm_button()
time.sleep(3)
self.assertEqual(self.port_management_page.get_text(), "添加成功", self.port_management_page.get_text())
self.assertEqual(self.search_mysql.search_mysql(self.search_create_portname), self.create_portname, self.search_mysql.search_mysql(self.search_create_portname))
# 编辑端口组
def test_2edit_port(self):
time.sleep(3)
# 点击编辑端口组按钮
self.port_management_page.click_edit_button()
time.sleep(3)
# 输入端口组名
self.create_edit_port_page.input_port_name(self.edit_portname)
# 输入端口组内容
self.create_edit_port_page.input_port_content(self.edit_portcontent)
# 点击确定按钮
self.create_edit_port_page.click_confirm_button()
time.sleep(3)
self.assertEqual(self.port_management_page.get_text(), "保存成功", self.port_management_page.get_text())
self.assertEqual(self.search_mysql.search_mysql(self.search_edit_portname), self.edit_portname1, self.search_mysql.search_mysql(self.search_edit_portname))
# 删除端口组
def test_3delete_port(self):
time.sleep(3)
# 点击删除端口组按钮
self.port_management_page.click_delete_button()
time.sleep(3)
# 点击确定按钮
self.port_management_page.click_confirm_button()
time.sleep(3)
self.assertEqual(self.port_management_page.get_text(), "删除成功", self.port_management_page.get_text())
self.assertEqual(self.search_mysql.search_mysql(self.search_create_portname), '数据库未找到该数据!', "删除失败!")
self.assertEqual(self.search_mysql.search_mysql(self.search_edit_portname), '数据库未找到该数据!', "删除失败!")

@classmethod
def tearDownClass(cls):
time.sleep(3)
cls.driver.quit()

if __name__ == "__main__":
unittest.main()
九、test_suite.py用于批量执行测试用例并生成测试报告,完整代码如下:
import unittest
import HTMLTestRunner
if __name__ == "__main__":
filepath = r".\report\htmlreport.html"
test_dir = r'.\testcases'
ftp = open(filepath,'wb')
suite = unittest.defaultTestLoader.discover(test_dir, pattern='zjtest*.py')
runner = HTMLTestRunner.HTMLTestRunner(stream = ftp, title = "测试报告")
runner.run(suite)
ftp.close()

猜你喜欢

转载自www.cnblogs.com/hahaxiaojingzi/p/11310290.html