python3+selenium自动化测试框架详解

发布时间:2024年01月04日

背景

为了更好的发展自身的测试技能,应对测试行业以及互联网行业的迭代变化。自学python以及自动化测试。

虽然在2017年已经开始接触了selenium,期间是断断续续执行自动化测试,因为还有其他测试任务,培训任务要执行…
前期建议大家能够学习python基本语法(python基础教程)

任务

搭建自动化测试框架,并能有效方便的进行测试,维护成本也要考虑其中。

过程

我的自动化框架可能不成熟,因为是自学的。请多包涵。也请大佬指导~

common

包含:基本的公共方法类,比如HTML报告、Log处理、发送邮件、基本页面对象等

其中pageObject里面是对各个测试系统操作页面的一个封装,以后用例的方法直接继承即可。可多次调用,维护起来比较方便。

conf

基本的系统参数配置信息,可以包含url,正确用户的信息,简单日志级别,某些输出位置,邮件信息等

data

对于数据驱动或者其他测试用例中需要测试的数据,之后测试用例流程不变,可以直接在文档中进行测试数据的修改。暂时采用excel。也可以采用csv,xml等等方法

log

日志输出,暂时包括了 log输出,htmlreport输出以及img的保存。

test

其中包含testcase以及testsuite两个模块

testcase 负责编写测试用例如果某个功能有多个py文件编写可以再新建一个目录。
testsuite 就是测试套件,可以按需求进行选择需要的测试项(包含测试用例以及测试类)
注意:使用ddt则不可以再使用addTest方式单独添加测试用例了。?

1

代码部分

- common中的BasePage

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

class BasePage():

?global logg

?logg = LogHandler().logger

?def __init__(self,driver,url=None):

??self.wd = driver

??self.wd.implicitly_wait(5)

??self.actions = ActionChains(self.wd)

??if url :

???self.url = url

??else:

???self.url = self.server_url_conf()

?#浏览器行为的一些方法

?def get_conf_url(self):

????????self.wd.get(self.url)

??self.wd.maximize_window()

??logg.debug("enter conf_url : " + str(self.url))

?def brower_close(self):

??return self.wd.close()

?def brower_quit_all(self):

??return self.wd.quit()

...???? 下面还有刷新,前进后退等

?#定位 这里通过 By.xx 方法

?def find_web_element(self,*loc):

??#self.wd.find_element(*loc)

??return self.wd.find_element(*loc)

?#元素操作

?def type_text(self,loc,text):

??return self.wd.find_element(*loc).send_keys(text)

???

?def clear_text(self,*loc):

??return self.wd.find_element(*loc).clear()

???

?def submit_func(self,*loc):

??return self.wd.find_element(*loc).submit()

?def click_btn(self,*loc):

??return self.wd.find_element(*loc).click()

???

????#鼠标相关

?def mouse_move_to_element(self,*loc):

??elem = self.find_web_element(*loc)

??self.actions.move_to_element(elem).perform()

... 下面还有点击,双击,右击的一些方法?

?#获取信息行为

?def get_web_url(self):

??return self.wd.current_url

?def get_title(self):

??return self.wd.title

?def get_element_text(self,*loc):

??return self.find_web_element(*loc).text

?#元素是否存在 是 True

?def check_element_isexist(self,loc):

??isexist = False

??try:

???EC.presence_of_element_located(loc)(self.wd)

???isexist = True

??except Exception as e:

???isexist = False

???logg.debug(' isexist or not :',exc_info = True)

??return isexist

?def check_element_has_text(self,loc,text):

????????pass #省略

??

?def check_element_isdisplayed(self,*loc):

????pass #省略

?????

?#生成图

?def __inser_img(self,passorfailed,imgname):

??time_loc = time.strftime("%m%d_%H%M%S",time.localtime())

??file_path = os.path.abspath(__file__)

??file_path = os.path.join(file_path+"/../../log/%s_%s.png" %(imgname,time_loc))

??self.wd.get_screenshot_as_file(file_path)

??logg.debug('insert_%s_img %s ' %(passorfailed,(file_path)))

?def insert_error_img(self,imgname):

??self.__inser_img("error",imgname)

?def insert_success_img(self,imgname):

??self.__inser_img("success",imgname)

?def insert_debug_img(self,imgname):

??self.__inser_img("debug",imgname)

?def server_url_conf(self):

??self.host = readconfig.ReadConfig().getserver('host')

??self.port = readconfig.ReadConfig().getserver('port')

??urlvalue = self.host + ":" + self.port

??return urlvalue

if __name__ == '__main__':

?test = BasePage(webdriver.Chrome())

?test.get_conf_url()

common中登录页的页面对象

包含了页面的一些方法比如

输入用户名,输入密码,点击登录

test中的 logintestcase

则直接使用 登录页面对象的 输入用户名,输入密码,点击登录即可

后期维护,如果元素变动,则只需要修改页面对象代码而对用例则无需修正

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

class AioLogin(BasePage):

?global logg

?logg = LogHandler().getlog()

?username_loc = (By.NAME, "username")

?password_loc = (By.CSS_SELECTOR, "input[type='password']")

?login_loc = (By.CLASS_NAME, "login-btn")

?login_loc_oem = (By.ID,"submit")

?check_login_loc = (By.CLASS_NAME,"error-tip")

?elements = [username_loc,password_loc,login_loc,check_login_loc]

?log_menu = (By.CSS_SELECTOR,"[name='log']")

?logg.debug(elements)

??

?def set_username(self,username):

??self.clear_text(*self.username_loc) #直接使用BasePage的方法

??self.type_text(self.username_loc,username)

??logg.info('Enter username: ' + username)

??sleep(0.1)

... 其他

logintest

这里使用了ddt数据驱动方法

from ddt import data,ddt,unpack

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

@ddt

class TestLogin(unittest.TestCase):

?global logg

?logg = LogHandler().getlog()

??

?@classmethod? #该类方法,执行中只会启动一次。区别于setUp的 每个用例都执行一遍

?def setUpClass(cls):

??cls.test = aiologinpage.AioLogin(webdriver.Chrome())

??cls.test.get_conf_url()

??# print('start TestSearch')

???

?@classmethod

?def tearDownClass(cls):

??# TestLogin().logg.info("brower quit")

??TestLogin().test.brower_close()

??pass

?logindata = ReadExcel().getValue('login')

??

?@data(*logindata)

?@unpack? #当有多组数据时,需要unpack

?def testcase2(self,username,passwd,result):

??logg.info(username+" " + passwd +" " +str(result))

??self.test.set_username(username) #用例直接使用登录页面对象,后期除了修改测试用例,否则无需变动

??self.test.set_password(passwd)

??self.test.type_login_btn()

???

??# 断言登录结果和预期结果是否一致

??self.assertTrue(self.test.check_login_result(result),

??????msg="\r login_test fail \r username :%s \r passwd : %s " %(username,passwd))

if __name__ == '__main__':

?unittest.main()

其他页面

比如我有个 创建设备分组的页面

我必须要先登录才可以执行下面的操作

此时,可以从conf中获取成功登录的用户名和密码,把correct_login方法写在登录页面对象中。

1

2

3

4

5

6

def correct_login(self):

??self.get_conf_url()

??self.userpasswd = self.correct_userpasswd_conf()

??self.set_username(self.userpasswd[0])

??self.set_password(self.userpasswd[1])

??self.type_login_btn()

之后,其他页面初始化时候直接调用这个correct_login即可登录

测试套件添加方法
TestSuite方法
#添加一个类
st1 = unittest.makeSuite(TestLogin)
#单独添加多个用例
st = unittest.TestSuite(map(TestClassName,[‘testcase1',‘testcase2']))
st = unittest.TestSuite(TestClaseeName(‘testcase1'))

#添加一个或者多个测试用例
st2 = unittest.TestSuite()
st2.addTests(map(TestCaseClassName,[‘testcase2',‘testcase1']))
st2.addTest(TestCaseClassName(‘testcase1'))
#添加一个类
st2.addTest(unittest.makeSuite(TestClassName))

TestLoader 方法
discovery 发现脚本
st = unittest.TestLoader().discovery(“dir_path”,pattern=“a*.py”)

#loadTestFromTestCase 加载 测试类
st1 = unittest.TestLoader().loadTestsFromTestCase(TestLoginCheck)
st2 = unittest.TestLoader().loadTestsFromTestCase(TestLogin)
stt = unittest.TestSuite()
stt.addTests([st1,st2])

?现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。
如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受
可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛
分享他们的经验,还会分享很多直播讲座和技术沙龙
可以免费学习!划重点!开源的!!!
qq群号:485187702【暗号:csdn11】

最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走!?希望能帮助到你!【100%无套路免费领取】

文章来源:https://blog.csdn.net/weixin_47648853/article/details/135386794
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。