python和selenium的web UI自动化测试

https://my.oschina.net/u/3041656/blog/857676

源码下载:https://pan.baidu.com/s/1jIqpu8A


之前分享了python和requests搭配实现的接口自动化测试框架,今天,我再来整理分析下基于python和selenium的web UI自动化测试,希望能对大家有所帮助,也是自己整理知识学习的方法,跟大家一起努力,奋斗在自动化测试的道路上。

其实UI自动化和接口自动化框架的设计思路大同小异,主要目的还是分离业务代码和测试数据,达到代码的复用,提高测试用例的可维护性以及最最重要的减少人工劳动力。那么就开始直接看正文吧。

设计目的:

分离业务代码和测试数据,提高代码可维护性,实现自动化,减少重复劳动,最终达到“偷懒”的目的,哈哈哈哈哈~~ 哎呦,不好意思,一不小心暴露了真相。小编是真的在一本正经的写代码啦。

框架目录结构:

        case:存放具体的测试代码

        comm:存放共通的方法

        file:存放测试用例等测试过程中用到的测试数据

        result:每次测试的log和测试报告的存放位置

        caseList:规定执行哪些测试

        config:配置静态数据

                                                                readConfig:读取config文件内容

                                                                runAll:测试执行入口文件

一起来看整个框架的搭建。

首先,要保证你的python已经安装了selenium包,如果你是用pip来管理自己的python环境的,那么你可以通过下面的命令来导入selenium模块:

pip install selenium
   
   

然后,你需要到网上去下载对应浏览器的驱动,这里小编使用的是chrome浏览器,(chrome下载地址:http://chromedriver.storage.googleapis.com/index.html)。下载完成之后呢,将下载的浏览器驱动放到本地的python安装目录下,这样就可以直接在框架中使用了。至此,必备的条件都有了,我们就可以开工啦。

这里呢,我们就只挑部分内容进行讲解,有许多跟接口测试框架相同或相似的方法和文件,就不一一进行二次说明了,第一次看的盆友们,有不明白的地方可以看这篇文章,进行补充学习https://my.oschina.net/u/3041656/blog/820023

打开浏览器:


   
   
  1. from selenium import webdriver
  2. class Driver:
  3. def __init__(self):
  4. self.browser = webdriver.Chrome()
  5. def open_browser(self):
  6. """
  7. Do something for browser
  8. :return: browser
  9. """
  10. # 窗口最大化
  11. self.browser.maximize_window()
  12. # 打开地址链接
  13. url = 'http://www.baidu.com'
  14. self.browser.get(url)
  15. return self.browser
  16. def close_browser(self):
  17. """
  18. quit browser
  19. :return:
  20. """
  21. self.browser.quit()

从上面的代码可以看出,我们进行了打开/关闭浏览器的方法定义,只有简单的几行代码,当然了,这里为了方便大家观看,我把url地址直接写了出来,在实际操作时,我们可以将其抽离出来,根据自己的需要,传入不同的url地址。这就留着让大家去自己实现吧。

一个简单的搜索栗子:


   
   
  1. from time import sleep
  2. from selenium import webdriver
  3. import unittest
  4. class Login(unittest.TestCase):
  5. def setUp(self):
  6. self.driver = webdriver.Chrome()
  7. # 窗口最大化
  8. self.driver.maximize_window()
  9. self.msg = '海贼王'
  10. self.url = 'http://www.baidu.com'
  11. def testSearch(self):
  12. """
  13. test body
  14. :return:
  15. """
  16. # open browser
  17. self.driver.get(self.url)
  18. sleep(3)
  19. # click search input
  20. self.driver.find_element_by_id('kw').click()
  21. sleep(1)
  22. # input value
  23. self.driver.find_element_by_id('kw').send_keys(self.msg)
  24. sleep(1)
  25. self.driver.find_element_by_id('su').click()
  26. sleep(1)
  27. def tearDown(self):
  28. self.driver.close()
  29. if __name__ == "__main__":
  30. unittest.main()

在上面的代码里,我们在百度里搜索了小编最爱的动漫,嘻嘻,是不是很开心啊,就这样边学边玩耍,感觉测试也是美美的。

selenium可以通过很多种方式来定位元素。这个读者可以自行学习。

大家看到了,这就是UI测试的雏形,有了这个雏形,我们就可以对它进行扩展,扩展,最后搭出框架来。

添加log日志:

在上面的基础上,我们可以添加执行时输出的log日志。所以开始写log文件,并将它放在comm文件夹下,作为共同方法来用。这部分内容在接口测试框架那里已经介绍过了,所以请还不清楚的朋友们移步此处:https://my.oschina.net/u/3041656/blog/820023

抽离出浏览器的相关操作:

我们可以将对浏览器的操作剥离出来,单独放到一个文件中,这样既清晰,又避免了重复的代码操作。而且维护起来也比较方便。


   
   
  1. from selenium import webdriver
  2. from comm.Log import MyLog as Log
  3. import readConfig
  4. import threading
  5. localReadConfig = readConfig.ReadConfig()
  6. class Driver:
  7. def __init__(self):
  8. self.log = Log.get_log()
  9. self.logger = self.log.get_logger()
  10. self.browser = webdriver.Chrome()
  11. def open_browser(self, name1, name2):
  12. """
  13. Do something for browser
  14. :return: browser
  15. """
  16. self.logger.info("Open browser")
  17. # 窗口最大化
  18. self.browser.maximize_window()
  19. # 打开地址链接
  20. url = localReadConfig.get_webServer(name1, name2)
  21. self.browser.get(url)
  22. return self.browser
  23. def close_browser(self):
  24. """
  25. quit browser
  26. :return:
  27. """
  28. self.browser.quit()
  29. self.logger.info("Quit browser")
  30. def get_driver(self):
  31. """
  32. get web driver
  33. :return:
  34. """
  35. return self.browser
  36. class MyDriver:
  37. driver = None
  38. mutex = threading.Lock()
  39. def __init__(self):
  40. pass
  41. @staticmethod
  42. def get_browser():
  43. if MyDriver.driver is None:
  44. MyDriver.mutex.acquire()
  45. MyDriver.driver = Driver()
  46. MyDriver.mutex.release()
  47. return MyDriver.driver
  48. if __name__ == "__main__":
  49. driver = MyDriver.browser()
  50. browser = driver.open_browser()

以上便是小编剥离出来的部分,并且将它放到了单独的线程中。

有木有觉得眼熟呢?其实就跟log的原理是一样的啦。这就是“举一反三”哦,套路就是那个套路,就看你怎么用了。

关于Element的那些事儿:

做过UI功能测试的朋友们应该都知道,元素是我们测试最基本也是最重要的东西,以为它是我们直接的操作对象,所以,处理好它们,我们就会省掉很多的麻烦,所以呢,接下来,小编将会继续分享自己处理element的一些方法,希望能对大家有所帮助,如果哪位大神有更好的方法,请一定要告诉小编哦!小编在此先谢过了!


   
   
  1. class Element:
  2. def __init__(self, activity_name, element_name):
  3. self.driver1 = Driver.get_browser()
  4. self.driver = self.driver1.get_driver()
  5. self.activity = activity_name
  6. self.element = element_name
  7. element_dict = get_el_dict(self.activity, self.element)
  8. self.pathType = element_dict.get('pathType')
  9. self.pathValue = element_dict.get('pathValue')
  10. def is_exist(self):
  11. """
  12. Determine element is exist
  13. :return: TRUE OR FALSE
  14. """
  15. try:
  16. if self.pathType == 'ID':
  17. self.driver.find_element_by_id(self.pathValue)
  18. return True
  19. if self.pathType == 'XPATH':
  20. self.driver.find_elements_by_xpath(self.pathValue)
  21. return True
  22. if self.pathType == 'CLASSNAME':
  23. self.driver.find_element_by_class_name(self.pathValue)
  24. return True
  25. if self.pathType == 'NAME':
  26. self.driver.find_element_by_name(self.pathValue)
  27. return True
  28. except NoSuchElementException:
  29. return False
  30. def wait_element(self, wait_time):
  31. """
  32. wait element appear in time
  33. :param wait_time: wait time
  34. :return: true or false
  35. """
  36. time.sleep(wait_time)
  37. if self.is_exist():
  38. return True
  39. else:
  40. return False
  41. def get_element(self):
  42. """
  43. get element
  44. :return: element
  45. """
  46. try:
  47. if self.pathType == 'ID':
  48. element = self.driver.find_element_by_id(self.pathValue)
  49. return element
  50. if self.pathType == 'XPATH':
  51. element = self.driver.find_elements_by_xpath(self.pathValue)
  52. return element
  53. if self.pathType == 'CLASSNAME':
  54. element = self.driver.find_element_by_class_name(self.pathValue)
  55. return element
  56. if self.pathType == 'NAME':
  57. element = self.driver.find_element_by_name(self.pathValue)
  58. return element
  59. except NoSuchElementException:
  60. return None
  61. def get_element_by_index(self, index):
  62. """
  63. get element by index
  64. :param index: index
  65. :return: element
  66. """
  67. try:
  68. if self.pathType == 'ID':
  69. element = self.driver.find_element_by_id(self.pathValue)
  70. return element[index]
  71. if self.pathType == 'XPATH':
  72. element = self.driver.find_elements_by_xpath(self.pathValue)
  73. return element[index]
  74. if self.pathType == 'CLASSNAME':
  75. element = self.driver.find_element_by_class_name(self.pathValue)
  76. return element[index]
  77. if self.pathType == 'NAME':
  78. element = self.driver.find_element_by_name(self.pathValue)
  79. return element[index]
  80. except NoSuchElementException:
  81. return None
  82. def get_element_list(self):
  83. """
  84. get element list
  85. :return: element list
  86. """
  87. try:
  88. if self.pathType == 'ID':
  89. element_list = self.driver.find_element_by_id(self.pathValue)
  90. return element_list
  91. if self.pathType == 'XPATH':
  92. element_list = self.driver.find_elements_by_xpath(self.pathValue)
  93. return element_list
  94. if self.pathType == 'CLASSNAME':
  95. element_list = self.driver.find_element_by_class_name(self.pathValue)
  96. return element_list
  97. if self.pathType == 'NAME':
  98. element_list = self.driver.find_element_by_name(self.pathValue)
  99. return element_list
  100. except NoSuchElementException:
  101. return None
  102. def click(self):
  103. """
  104. click element
  105. :return:
  106. """
  107. element = self.get_element()
  108. time.sleep(1)
  109. element.click()
  110. def send_key(self, key):
  111. """
  112. input key
  113. :param key: input value
  114. :return:
  115. """
  116. element = self.get_element()
  117. time.sleep(1)
  118. element.clear()
  119. element.send_keys(key)
  120. def input_keys(self, index, key):
  121. """
  122. By index send key
  123. :param index: index
  124. :param key: key
  125. :return:
  126. """
  127. element = self.get_element_by_index(index)
  128. time.sleep(1)
  129. element.clear()
  130. element.send_keys(key)
  131. def get_text_value(self):
  132. """
  133. get attribute
  134. :return:
  135. """
  136. element = self.get_element()
  137. value = element.get_attribute('text')
  138. return str(value)

这是小编写的,目前能用到的关于element的方法了,累觉不爱啊~

但是,生活还要继续,工作还未完成。所以,请让我讲完剩下的代码吧!!!

那些让人费神的测试数据文件:

每一个好的测试,都离不开一份好的测试用例数据,那么,这么多的数据,我们要怎样进行管理才能既不乱又方便以后对数据进行更改维护呢?下面,小编就要告诉朋友们一个重磅消息,敲黑板!!!

其实,小编也不知道有什么好办法,小编就是使用excel文件来对测试用例进行统一管理的。请看下面:

形式就是这么个形式,内容就随便你们怎么修改了。毕竟我也只能帮你们到这里了。至于对excel文件内容的读取,在接口测试那篇博文中也有详细介绍哦。不明白的同学请移步:https://my.oschina.net/u/3041656/blog/820023

其实,出来测试用例,还有一个数量庞大的数据群体,快猜猜它们是谁???

当当当,答案就是:元素定位的数据,包括:id,name,classname,xpath等等,这些数据可是我们在测试过程中找到页面元素的不二法门哦。。。所以各位朋友一定要注意啦,一定要处理好它们。

请看下面:

愚蠢的小编就用xml文件来管理啦。

是不是又有人想问怎么读取xml文件了?嘿嘿。。。我不会告诉你的,因为我在前面的博文里已经讲过啦!讲过啦!过啦!啦!!

至此呢,今天的内容也结束了,希望对大家有所启发和帮助,虽然讲的有些凌乱,不过只要弄懂了这些划分和实现方法,我相信,你也一定可以写出自己满意的UI自动化测试框架。所以,我们一起加油吧。

PS:有些没有提到的部分,由于跟之前介绍接口自动化框架的内容一样,所以就不再累述,有想了解的朋友,移步此处即可。谢谢!https://my.oschina.net/u/3041656/blog/820023

 

本文为原创文章,转载请注明原文地址,谢谢大家的支持。希望大家一起努力成长。




如果觉得本文的文章写得很好,打个赏,多少都行~~~


如果觉得本文的文章写得很好,打个赏,多少都行~~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值