PyQt的一个UI单元测试框架思路-程序员宅基地

專 欄


丁果,Python中文社区作者。对 django、pyqt、opencv、tornado感兴趣。
GitHub:https://github.com/lidingke

一、思路

PyQt是个 相当灵活的UI框架,不过,这个Qt的Python版本一直没有一个好用的针对UI的单元测试工具。

PyQt里的逻辑层都是采用信号槽的方式连接的,我们可以通过拦截并重建信号槽的方式,动态生成一个单元测试的脚本。按这个思路写了一个单元测试的工具。如果需要的人多的话,我就把这个模块做成一个单元测试的框架。

二、demo

一个好用的工具应该是非侵入式的,接口合理且命名规范,符合大多数人使用习惯的,我认为这样一个PyQt的单元测试用例应该长这样子。

主要的动作就是,按照源代码中按钮的信号槽连接的调用链,触发按钮的点击实践,执行点击按钮后的逻辑。

在上述代码中,首先单元测试的入口是启动界面的代码,也就是test_start_main_ui函数,这段代码是最简单的一个PyQt的界面启动代码,其中不一样的是启动了一个线程用于执行单元测试。

而单元测试的函数是这样的,首先初始化一个参数为view的实例的类,这个类用于拦截信号槽,并执行信号动作,我把这个类命名为Knife。

接下来就是执行view下面的target_button的点击事件,这一系列的成员函数是根据原始view里面的信号槽连接代码动态生成的,后面会讲具体方法。

触发点击事件后,结果显示在一个label上,assert一下这个结果是否正确就行了。

GIF是一个演示实例,QLineEdit里面输入一个数,按一下-1s的按钮(QPushButton),会在最右的label上将该数减一之后显示,Demo GUI部分的代码看这里。

三、Qt与PyQt

Qt中信号槽是个不可或缺的概念,和元对象系统之类的东西组成了Qt的基础组件。但对于起源于上古时代的Qt,这些东西很多是为了弥补当时C++的不足,对于Python这种强类型的语言来说并不是那么不可或缺,比如信号槽本质上就是观察者模式,完全可以自己实现一个,我自己的实现可以看这里。

而Qt的元对象系统是一个代码生成框架,给C++提供了自省的能力,但Python这种动态语言在语言层面上就有强大的自省功能,所以我平时用PyQt的时候一般就把它当一个UI库用,其他的东西比如线程、信号槽、串口等都用Python版本的。

四、拦截的实现

在PyQt中,信号槽连接的写法一般是这样的。

signal_instance.connect(slot_name)

所以,我这个版本的拦截信号槽的功能的实现思路就是用正则匹配源代码,从符合这一模式的

语句中解析出信号的发送端和槽函数,将槽函数重新添加进新的生成的自定义信号槽中。

信号槽重连接

之前说Python的自省能力强大,现在有个非常实际的例子就是,在Python中可以动态的获取源代码。这个功能用到的Python 标准库中的inpect库,示例如下。import inspect

print inspect.getsource(inspect.isclass)

这段代码的功能是将inspect库中的isclass函数的源代码打印出来。inspect模块是个很神奇的模块,如果你对闭包和协程不理解的话也可以调用该模块中的相应代码看看。

在程序中还用到了code.co_names这个东西,用来高效的查看函数的源代码里有没有"connect"字符串。

五、程序结构

这里是部分程序源代码,省略了代码细节,源代码可以看这个git仓库

这里用一个叫Knife的类来实现,在重建新的信号函数的时候我希望信号函数的调用方式和程序源代码里的调用方式保持一致,这里就得采用动态的生成方式。而涉及到类成员的动态生成,采取一种不一样的写法比较好,比如把生成的时间从init方法中提前到new方法中。

widget_instance就是包含信号槽的类,因为我写GUI都是采用MVC的方式,需要导出并拦截的信号槽都在一个类里面,这个类传入的时候已经是个实例了。动态解析该实例源代码,并动态生成新的信号去装载信号槽。

其中,还有个问题,有些调用可能嵌套的好几层,比如像这样。

self.mother.father.son.dog.clicked()

这样的操作需要用递归生成,就像这样。

调用链中自定义生成的节点类为SubNode,槽函数如果动态获取不到时,会返回一个自定义异常FailAttr。

具体的请看Github

六、知识点详解

这一栏列出一些特殊的知识点。

1、getattr,setattr,hasattr:动态的获取对象的方法,给一个对象动态的添加方法,判断一个对象是否含有某方法。

2、__new__魔法方法:这个方法在__init__之前,是真正的类初始化函数。要注意的是new方法需要返回的是类实例,就像源代码中的写法。而在__new__方法中是使用不了实例方法的,得用staticmethod和classmethod装饰器去修饰。

3、staticmethod,classmethod:都是类方法的装饰器,只不过classmethod装饰过的成员方法第一个参数是cls,staticmethod装饰过的东西不引入这个参数,相当于一个纯函数,叫做静态方法。这里的两个函数都可以用classmethod装饰,不过parser_slots函数中用不到cls,我就用staticmethod装饰了。

4、用类方法去区别一些特殊操作,这一方式最常见的就是Django的ORM,将数据库操作和表单的定义分为类方法和成员方法。所以大家理解不了类方法和元类的时候可以去研究下Django的ORM。

5、列表生成式和正则表达式之类的就不解释了。

感觉篇幅有点长,其他的细节如果有需要的话在下一篇文章里解释。如果大家真需要,可以考虑专门搞成一个开源项目。


长按扫描关注Python中文社区,

获取更多技术干货!

    

Python 中 文 社 区

Python中文开发者的精神家园

合作、投稿请联系微信:

pythonpost

— 人生苦短,我用Python —
1MEwnaxmMz7BPTYzBdj751DPyHWikNoeFS



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/BF02jgtRS00XKtCx/article/details/78614477

智能推荐

874计算机科学基础综合,2018年四川大学874计算机科学专业基础综合之计算机操作系统考研仿真模拟五套题...-程序员宅基地

文章浏览阅读1.1k次。一、选择题1. 串行接口是指( )。A. 接口与系统总线之间串行传送,接口与I/0设备之间串行传送B. 接口与系统总线之间串行传送,接口与1/0设备之间并行传送C. 接口与系统总线之间并行传送,接口与I/0设备之间串行传送D. 接口与系统总线之间并行传送,接口与I/0设备之间并行传送【答案】C2. 最容易造成很多小碎片的可变分区分配算法是( )。A. 首次适应算法B. 最佳适应算法..._874 计算机科学专业基础综合题型

XShell连接失败:Could not connect to '192.168.191.128' (port 22): Connection failed._could not connect to '192.168.17.128' (port 22): c-程序员宅基地

文章浏览阅读9.7k次,点赞5次,收藏15次。连接xshell失败,报错如下图,怎么解决呢。1、通过ps -e|grep ssh命令判断是否安装ssh服务2、如果只有客户端安装了,服务器没有安装,则需要安装ssh服务器,命令:apt-get install openssh-server3、安装成功之后,启动ssh服务,命令:/etc/init.d/ssh start4、通过ps -e|grep ssh命令再次判断是否正确启动..._could not connect to '192.168.17.128' (port 22): connection failed.

杰理之KeyPage【篇】_杰理 空白芯片 烧入key文件-程序员宅基地

文章浏览阅读209次。00000000_杰理 空白芯片 烧入key文件

一文读懂ChatGPT,满足你对chatGPT的好奇心_引发对chatgpt兴趣的表述-程序员宅基地

文章浏览阅读475次。2023年初,“ChatGPT”一词在社交媒体上引起了热议,人们纷纷探讨它的本质和对社会的影响。就连央视新闻也对此进行了报道。作为新传专业的前沿人士,我们当然不能忽视这一热点。本文将全面解析ChatGPT,打开“技术黑箱”,探讨它对新闻与传播领域的影响。_引发对chatgpt兴趣的表述

中文字符频率统计python_用Python数据分析方法进行汉字声调频率统计分析-程序员宅基地

文章浏览阅读259次。用Python数据分析方法进行汉字声调频率统计分析木合塔尔·沙地克;布合力齐姑丽·瓦斯力【期刊名称】《电脑知识与技术》【年(卷),期】2017(013)035【摘要】该文首先用Python程序,自动获取基本汉字字符集中的所有汉字,然后用汉字拼音转换工具pypinyin把所有汉字转换成拼音,最后根据所有汉字的拼音声调,统计并可视化拼音声调的占比.【总页数】2页(13-14)【关键词】数据分析;数据可..._汉字声调频率统计

linux输出信息调试信息重定向-程序员宅基地

文章浏览阅读64次。最近在做一个android系统移植的项目,所使用的开发板com1是调试串口,就是说会有uboot和kernel的调试信息打印在com1上(ttySAC0)。因为后期要使用ttySAC0作为上层应用通信串口,所以要把所有的调试信息都给去掉。参考网上的几篇文章,自己做了如下修改,终于把调试信息重定向到ttySAC1上了,在这做下记录。参考文章有:http://blog.csdn.net/longt..._嵌入式rootfs 输出重定向到/dev/console

随便推点

uniapp 引入iconfont图标库彩色symbol教程_uniapp symbol图标-程序员宅基地

文章浏览阅读1.2k次,点赞4次,收藏12次。1,先去iconfont登录,然后选择图标加入购物车 2,点击又上角车车添加进入项目我的项目中就会出现选择的图标 3,点击下载至本地,然后解压文件夹,然后切换到uniapp打开终端运行注:要保证自己电脑有安装node(没有安装node可以去官网下载Node.js 中文网)npm i -g iconfont-tools(mac用户失败的话在前面加个sudo,password就是自己的开机密码吧)4,终端切换到上面解压的文件夹里面,运行iconfont-tools 这些可以默认也可以自己命名(我是自己命名的_uniapp symbol图标

C、C++ 对于char*和char[]的理解_c++ char*-程序员宅基地

文章浏览阅读1.2w次,点赞25次,收藏192次。char*和char[]都是指针,指向第一个字符所在的地址,但char*是常量的指针,char[]是指针的常量_c++ char*

Sublime Text2 使用教程-程序员宅基地

文章浏览阅读930次。代码编辑器或者文本编辑器,对于程序员来说,就像剑与战士一样,谁都想拥有一把可以随心驾驭且锋利无比的宝剑,而每一位程序员,同样会去追求最适合自己的强大、灵活的编辑器,相信你和我一样,都不会例外。我用过的编辑器不少,真不少~ 但却没有哪款让我特别心仪的,直到我遇到了 Sublime Text 2 !如果说“神器”是我能给予一款软件最高的评价,那么我很乐意为它封上这么一个称号。它小巧绿色且速度非

对10个整数进行按照从小到大的顺序排序用选择法和冒泡排序_对十个数进行大小排序java-程序员宅基地

文章浏览阅读4.1k次。一、选择法这是每一个数出来跟后面所有的进行比较。2.冒泡排序法,是两个相邻的进行对比。_对十个数进行大小排序java

物联网开发笔记——使用网络调试助手连接阿里云物联网平台(基于MQTT协议)_网络调试助手连接阿里云连不上-程序员宅基地

文章浏览阅读2.9k次。物联网开发笔记——使用网络调试助手连接阿里云物联网平台(基于MQTT协议)其实作者本意是使用4G模块来实现与阿里云物联网平台的连接过程,但是由于自己用的4G模块自身的限制,使得阿里云连接总是无法建立,已经联系客服返厂检修了,于是我在此使用网络调试助手来演示如何与阿里云物联网平台建立连接。一.准备工作1.MQTT协议说明文档(3.1.1版本)2.网络调试助手(可使用域名与服务器建立连接)PS:与阿里云建立连解释,最好使用域名来完成连接过程,而不是使用IP号。这里我跟阿里云的售后工程师咨询过,表示对应_网络调试助手连接阿里云连不上

<<<零基础C++速成>>>_无c语言基础c++期末速成-程序员宅基地

文章浏览阅读544次,点赞5次,收藏6次。运算符与表达式任何高级程序设计语言中,表达式都是最基本的组成部分,可以说C++中的大部分语句都是由表达式构成的。_无c语言基础c++期末速成