微信小程序UI自动化测试实践:Minium+PageObject

小程序架构上分为渲染层逻辑层,尽管各平台的运行环境十分相似,但是还是有些许的区别(如下图),比如说JavaScript 语法和 API 支持不一致,WXSS 渲染表现也有不同,所以不论是手工测试,还是UI自动化测试,都必须要在 iOS 和 Android 上分别检查小程序的真实表现。

由于生态方面的原因,目前可选择的小程序UI自动化框架较少。在框架选取过程中,我考察了Appium、Airtest和Minium三个框架,并将三者做了对比,形成了以下图表:

Appium实现微信小程序自动化测试的手段基本上还是套用针对 Hybrid App 的测试方案,通过定位H5 App资源控件,并结合屏幕坐标的方式来操控小程序的页面元素;网易推出的Airtest则是基于图像识别和Poco控件识别,之前也对此框架做过比较深入的了解,但是和Appium一样,对于小程序自动化测试来说,以上两者无法深入小程序逻辑层,只能作用于渲染层,从另外一个角度来说,这两个框架还属于黑盒自动化测试的范畴。

01

Minium

接下来再介绍一下今天的主角:Minium。它是微信小程序官方推出自动化框架,提供了 Python3 和 JavaScript 版本(后者目前已停止维护,后文中的minium单指Python版本),目前最新的版本为1.0.0b2。minium不仅限于 UI 自动化,它还提供了很多有用的特性,比如说支持调用和 Mock 部分 wx 对象上的接口,支持获取和设置小程序页面数据,支持直接触发小程序元素绑定事件等等。

另外,minium提供一个基于unittest封装好的测试框架,利用这个简单的框架对小程序测试也可以起到事半功倍的效果。有了以上功能,不但可以简化用例的一些前期准备工作,更可以对小程序做更针对和更全面的测试。

minium的下载安装和官方文档,可以在代码库查看。官方文档写的还算较为清晰,除此之外,以下网站在学习过程中也有帮助:

  • 微信开放社区: 一些minium使用方面的问题,可以在右上角搜索 "minium" 寻找答案或发起提问;
  • 微信开发者工具: minium与微信开发者工具强关联,开发调试脚本都需要使用微信开发者工具;
  • Minium Demo: 官方提供的python版本的demo,内容非常简单,可以用来简单熟悉一下框架,若要运行demo需要先下载示例小程序代码;

02

Minium + Page Object

早期 GUI 自动化测试脚本,无论是Selenium还是UFT,脚本通常是由一系列的页面控件的顺序操作组成的,有点像操作级别的“流水账”,这主要体现在以下几个方面:

  • 脚本逻辑层次不够清晰,属于 All-in-one 的风格,既有页面元素的定位查找,又有对元素的操作;
  • 脚本的可读性差,在实际项目中,很难从代码中直观看出到底脚本在操作哪个控件,并且脚本的每一行都直接描述各个页面上的元素操作,无法直观的看出脚本更高层的业务测试流程;
  • 通用步骤会在大量测试脚本中重复出现;

Page Object 就是为了解决以上问题而出现的,它是UI自动化测试项目开发实践的最佳设计模式,采用分层封装的设计思想,不同层关心不同的问题。页面对象层只关心元素定位问题,测试用例只关心测试的数据。通过对界面元素和功能模块的封装减少冗余代码,在后期维护中,若元素定位或功能模块发生变化,只需要调整页面元素或功能模块封装的代码,显著提高测试用例的可维护性。

基于PO模式,小程序UI自动化测试Demo项目的目录结构及说明如下:

  • cases/: 存放业务测试用例;
  • outputs/: Minium测试报告;
  • pages/:页面对象模型;
  • *config.json:Minium项目配置文件;
  • suite.json:Minium测试计划文件;
  • route.py:统一存放小程序页面路由;
  • utils.py:存放一些公共方法;

03

具体代码

下面从具体代码入手,简单讲述一下项目的设计思路。

首先是BasePage,它是页面模型基类,用于封装所有页面公用的方法。

  1. import

  2. abc

  3. import

  4. time

  5. cla

  6. ss

  7. BasePage

  8. (

  9. abc.ABC

  10. ):

  11. def

  12. __init__

  13. (

  14. self, mini, route, title=""

  15. ):

  16. self

  17. .mini

  18. =

  19. mini

  20. self

  21. .route

  22. =

  23. route

  24. self

  25. .title

  26. =

  27. title

  28. def

  29. open

  30. (

  31. self

  32. ):

  33. """跳转到小程序目标页面"""

  34. self

  35. ._open(

  36. self.route, self.title

  37. ,

  38. open_type

  39. ='

  40. redirect

  41. ')

  42. def

  43. check_element

  44. (

  45. self

  46. ):

  47. """页面元素审查

  48. 在子类中实现此方法时,建议使用Minium框架中提供的断言方法,原因如下:

  49. 调用 Minium 框架提供的断言方法,会拦截 assert 调用,记录运行时数据和截图,自动在测试报告

  50. 中生成截图 (需要在配置文件中将 assert_capture 设置为True)

  51. 但是如果直接assert或使用unittest.TestCase提供的断言,当断言失败时,无法自动生成截图

  52. """

  53. raise

  54. NotImplementedError

  55. def

  56. on_page

  57. (

  58. self, route,

  59. title

  60. =

  61. None

  62. ,

  63. wait_util_page_contain_keys

  64. :

  65. list

  66. =

  67. None

  68. ):

  69. """通过对title和route断言,校验跳转进入的当前页是否符合预期"""

  70. if

  71. wait_util_page_contain_keys

  72. is not

  73. None

  74. and

  75. isinstance(

  76. wait_util_page_contain_keys, list

  77. ):

  78. self

  79. .mini.page.wait_data_contains

  80. (

  81. wait_util_page_contain_keys

  82. )

  83. else

  84. :

  85. time.sleep(2

  86. )

  87. self

  88. .mini.assertEqual

  89. (

  90. self.current_route, route,

  91. msg="页面路由不匹配, 预期:{},实际:{}".format(

  92. route, self.current_route)

  93. )

  94. if

  95. title

  96. :

  97. self

  98. .mini.assertEqual

  99. (

  100. self.current_title, title

  101. ,

  102. msg="页面标题不匹配, 预期:{},实际:{}".format

  103. (title, self.current_title)

  104. )

  105. @property

  106. def

  107. current_title

  108. (

  109. self

  110. ) ->

  111. str

  112. :

  113. """获取当前页面 head title, 具体项目具体分析,以下代码仅用于演示"""

  114. return

  115. self

  116. .mini.page.get_element

  117. ("

  118. XXXXXX

  119. ").inner_text

  120. @property

  121. def

  122. current_route

  123. (

  124. self

  125. ) ->

  126. str

  127. :

  128. """获取当前页面route, 具体项目具体分析, 以下代码仅用于演示"""

  129. return

  130. self

  131. .mini.app.get_current_page

  132. ().path

  133. def

  134. _open(

  135. self, route, title

  136. ,

  137. open_type

  138. =

  139. None

  140. ):

  141. """

  142. 小程序页面跳转可以使用以下三个方法, 一些区别如下:

  143. 1.`navigate_to`: 此方法会保留当前页面,并跳转到应用内的某个页面(不能跳到tabbar页面). 小程序中页面栈最多十层, 如果超过十层时,再使用此方法

  144. 跳转页面, 会抛出以下异常:`minium.framework.exception.MiniAppError: webview count limit exceed`. 因此需要在运行用例后及时清除页面栈;

  145. 2. `redirect_to`: 关闭当前页面,重定向到应用内的某个页面,使用此方法跳转页面时,会替换页面栈,因此页面栈不会超限,但是也导致不支持页面回退;

  146. 3. `relaunch`: 关闭所有页面,清空页面栈,打开到应用内的某个页面;

  147. """

  148. open

  149. _type = '

  150. redirect

  151. '

  152. if

  153. open_type

  154. is

  155. None

  156. else

  157. open_type

  158. if

  159. open_type

  160. .lower

  161. () == "

  162. navigate

  163. ":

  164. self

  165. .mini.app.navigate_to

  166. (

  167. route

  168. )

  169. elif

  170. open_type.lower

  171. () == "

  172. redirect

  173. ":

  174. self

  175. .mini.app.redirect_to

  176. (

  177. route

  178. )

  179. else

  180. :

  181. self

  182. .mini.app.relaunch

  183. (

  184. route

  185. )

  186. self

  187. .on_page

  188. (

  189. route, title

  190. )

具体业务的页面模型对象都需要继承BasePage,以IndexPage为例,代码如下所示:

 
  1. from

  2. pages.BasePage

  3. import

  4. BasePage

  5. from

  6. route

  7. import

  8. XXXXX

  9. class

  10. IndexPage

  11. (

  12. BasePage

  13. ):

  14. locators

  15. = {

  16. "

  17. AAA

  18. ": "

  19. view#aaa

  20. ",

  21. "

  22. BBB

  23. ": "

  24. view.bbb>image

  25. "

  26. }

  27. def

  28. check_element

  29. (

  30. self

  31. ):

  32. self

  33. .

  34. mini.assertTrue

  35. (

  36. self.mini.page.element_is_exists(IndexPage.locators['AAA']) is True

  37. )

  38. self

  39. .mini.assertTrue

  40. (

  41. self.mini.page.element_is_exists(IndexPage.locators['BBB']) is True

  42. )

  43. def

  44. click_query_btn

  45. (

  46. self

  47. ):

  48. self

  49. .mini.page.get_element

  50. ("

  51. view

  52. ", inner_text="

  53. xxxx

  54. ").click()

  55. self

  56. .on_page

  57. (route=

  58. XXXXX.XXXX.route

  59. , title=

  60. XXXXX.XXXX.title

  61. )

BaseEntity为测试用例基类,用于统一设置用例准备和清理工作,所有项目的测试用例都继承此类:

 
  1. from

  2. pathlib

  3. import

  4. Path

  5. import

  6. minium

  7. class

  8. BaseEntity

  9. (

  10. minium.MiniTest

  11. ):

  12. """测试用例基类"""

  13. @classmethod

  14. def

  15. setUpClass

  16. (

  17. cls

  18. ):

  19. super

  20. (

  21. BaseEntity, cls

  22. )

  23. .setUpClass

  24. ()

  25. output_dir =

  26. Path

  27. (

  28. cls.CONFIG.outputs

  29. )

  30. if

  31. not

  32. output_dir.is_dir

  33. ():

  34. output_dir

  35. .mkdir

  36. ()

  37. @classmethod

  38. def

  39. tearDownClass

  40. (

  41. cls

  42. ):

  43. super

  44. (

  45. BaseEntity, cls

  46. )

  47. .tearDownClass

  48. ()

  49. cls

  50. .app.go_home

  51. ()

  52. def

  53. setUp

  54. (

  55. self

  56. ):

  57. super

  58. (

  59. BaseEntity, self

  60. )

  61. .setUp

  62. ()

  63. def

  64. tearDown

  65. (

  66. self

  67. ):

  68. super

  69. (

  70. BaseEntity, self

  71. )

  72. .tearDow

  73. n

  74. ()

cases.Moudle_1.index_test.IndexTest代码内容如下:

  1. from

  2. cases

  3. import

  4. BaseEntity

  5. from

  6. pages.Moudle_1.IndexPage

  7. import

  8. IndexPage

  9. from

  10. route

  11. import

  12. XXXXX

  13. class

  14. ParkInd

  15. exTest(

  16. BaseE

  17. ntity):

  18. def

  19. test_index_page

  20. (

  21. self

  22. ):

  23. index_page

  24. = IndexPage(

  25. self, XXXXX.INDEX.route, XXXXX.INDEX.title

  26. )

  27. index_page.open

  28. ()

  29. index_page.check_element

  30. ()

  31. index_page.click_query_btn

  32. ()

总结:

  • 优点:PO模式对页面界面交互细节进行了封装,而测试用例基于页面对象完成具体操作,这样可以使我们的自动化测试脚本案例更关注业务,而非界面细节,提高了测试案例的可读性。

  • 缺点(个人观点):开发和维护页面对象的类(Page Class),是一件很耗费时间和体力的事儿。
  • 待研究方案:小程序页面对象自动生成,不用再手工维护 Page Class ,只需要提供页面路由,就会自动生成这个页面上控件的定位信息,并自动生成 Page Class;

 

总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

 

          视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取。

  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
pytest ui自动化测试实战主要包括安装并配置环境、练习pytest基本使用、练习selenium基本使用以及使用pytest和selenium实现UI自动化测试四个部分。在练习pytest基本使用中,我们可以通过编写简单的用例格式来实现对测试目的和要求的覆盖。而在练习selenium基本使用中,我们可以使用脚本语言来模拟用户行为操作,接近真实用户场景,实现对web页面的自动化测试。通过这些实践,我们可以了解基于pytest和seleniumUI自动化测试的基本思路,并熟悉这两种测试工具的基本操作。此外,pytest还是一个非常成熟的Python测试框架,它具有简单的用例编写格式和丰富的插件,如pytest-html和pytest-rerunfailures等,可以生成漂亮的测试报告并实现失败用例的重复执行。通过实战,我们可以基本掌握pytest的使用方法。另外,还可以基于pytest实现测试用例收集方案、自定义参数化方案、页面元素定位数据存储方案、测试用例数据存储和维护方案等,以避免重复设计和维护复杂的问题。此外,还可以修改定制并汉化html测试报告,使其更加简洁、美观、易读。同时,还可以封装集成selenium、appiumminium和WinAppDriver等工具,以更好地支持不同平台和应用的自动化测试。总之,通过pytest ui自动化测试实战,我们可以全面了解和掌握UI自动化测试的基本原理和实践技巧。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [软件测试案例|使用 pytest+selenium 进行UI自动化测试](https://blog.csdn.net/qq_41640218/article/details/124031645)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [基于pytest设计自动化测试框架实战](https://blog.csdn.net/hotswwkyo/article/details/103211805)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值