unittest+request+htmltestrunner为什么强于pytest+request+allure?

关于接口自动化框架python的实现方案,主流的就unittest/pytest+request+htmltestrunner/allure。

而unittest库相比于pytest在网上被各个博主喷的体无完肤,没有mark标记共功能,没有用例重跑机制、测试报告不如allure好看功能不如allure强大等等。但是我们深度思考后能否给自己提个疑问,这些所谓的原因是接口自动化解决方案的核心需求吗?如果一套框架的功能支持不了开发全自动化的测试代码,或者开发测试代码时不能自由的选择测试范围并执行后确认测试代码是能正常工作的,不能高效的支撑生产环境巡检需求,不能在测试执行不通过时给开发人员提供有效的信息,那么用例有mark功能、用例能够重跑、测试报告再漂亮且功能强大有什么用呢?

这篇文章将讲述在unittest和pytest之间,为什么要坚定不宜的选择unittest而放弃pytest。

一套好用、好落地的接口自动化框架解决方案,我认为应该有如下的价值

1、部署简单。标准:当你换一家公司时,实现了公司系统的登录功能接口自动化框架即可工作起来了

2、能够开发出全自动化的测试代码而且很方便,方便用户开发测试代码

3、能够支持多项目(应用)

4、能够支持多样化的生产环境巡检场景需求+测试环境多样化的测试代码执行需求

5、用户集成测试代码逻辑简单,即设置参数模板→发送请求→断言,开发测试代码的逻辑无限接近于手工测试接口工具如postman

6、框架的结构设计清晰,拓展性强,很容易在此基础上开发新的功能

7、能为开发定位问题提供有效的接口数据交互信息

8、接入新的项目时配置时间成本无限低

9、代码分支维护工作量无限低,无论是基于jenkins或时devops实现的ci,测试运行的仓库唯一、分支唯一(master分支)

以上是此时能够想到的,之后发现有遗漏再做补充,其中红色字是价值中的核心

一、unittest+request+htmltestrunner相比pytest+request+allure更加原生。

1、pytest需要单独安装,unittest是标准库,无需安装

2、allure需要安装java环境,allure也需要独立安装,而htmltestrunner可以集成到框架本地

3、支持pytest+allure需要安装大量其它库

结合上述的原因,unittest实现方案比pytest更加原生,在部署时会方便很多。如果你是框架的提供者,你会觉得这种不够原生的方式也没有什么,然而对于去开发测试代码的用户来说,他们对python的熟悉程度是有限的,尤其是还要安装python环境、java环境、allure、pytest、支持pytest+allure的库,对于用户来说一点也不友好,如果是一个菜鸟新手,可能这一套部署下来都直接懵逼了。

接口自动化框架部署时,大都会把需要安装的库放在requirements.txt中。之所有说unittest原生,在部署上可以直接一步到位。unittest无需安装、htmltestrunner可以直接集成到本地,唯一需要安装的就只是requests库了。如果框架有集成一些中间件的功能,那需要安装对应中间件访问的库即可。

部署unittest接口自动化框架只有两步:

1、安装python

2、安装微量requirements.txt中的库,安装命令: pip install -r .\requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/

下面我可以给大家看下requirements.txt中的内容

如果你的框架没有集成中间件或者图形文字,那其实只需要安装requests库就行了。而pytest开发的框架的requirements.txt中,要安装的库至少30个。

htmltestrunner是直接集成到本地的:

实不相瞒,pytest繁重的部署工作确实是直接劝退我的一个很大的原因。易用性很差。

二、用例mark功能和用例重跑机制对unittest不是问题,并且二开的mark功能比pytest的mark功能好用

关于这一点,可以查看我之前的文章,链接:unittest这样实现用例打标签功能比pytest的标签功能更好用

三、pytest对多项目(应用)的支持存在天然缺陷,对生产巡检需求的支持非常有限

首先,还是先解释下何为支持多项目(应用),即执行多个项目的测试代码的效果是一次执行多份报告:

这是一个很重要的功能设计,如果支持不了多项目的效果。那么在CI时必定时多个仓库多个jenkins的job的这种形式去管理集成的各个项目。在实际工作中,公司的多个子系统之间一定会存在功能交互的测试场景,如果不能实现多项目的效果,那么这种子系统交互的测试场景是没办法开发测试代码的。

那为什么会说pytest对多项目(应用)的支持存在天然缺陷,对生产巡检需求的支持非常有限呢?

答案就是pytest加载用例的设计机制无法满足一次运行多份报告的效果。pytest没有unittest测试类的概念,它没有按测试类去找测试方法的用例加载机制,它只有测试方法的概念。也就是多个项目的所有测试方法放在那里,你想执行哪些测试方法通过运行指定mark的方式去执行,这样效果就是一次执行一份报告。而unittest加载用例机制是有测试类的概念的,可以通过discover方式轻松的去划分多个项目的测试代码来定义测试范围,从而实现一次执行多份报告的效果。这个更详细的解释可以看我之前的文章unitttest如何设计支持运行多个应用的接口自动化框架(二)

四、allure功能强大也意味着冗余

其实这点我是不想讲的,但是不少人拿allure对比htmltestrunner时的说辞就是allure更好看、功能更加强大什么的,甚至以此认为结合allure的pytest就比结合htmltestrunner的unittest更好用更有逼格。我承认allure在报告里做了菜单并且ui确实比htmltestrunner更加好,但htmltestrunner的设计也非常好啊,该有的都有,精而巧啊。我想没有人一直会盯着测试报告来回点击欣赏吧,而allure里的那些拓展比如标题、测试步骤等等是可以在测试代码里实现的啊。再说了接口测试本身就是要用接口去体现信息交互啊,加汉字的测试步骤不是画蛇添足吗?而allure在部署时安装各种库还要安装java环境,htmltestrunner可以集成到本地,无需安装,这个不比好看的ui更有价值吗?

htmltestrunner报告的饼图、数据视图、折线图、柱状图一个也不少啊

另外,htmltestrunner有一个设计我非常喜欢,就是这个保存最近10次测试结果的设计:

为什么呢,这个设计帮助我完美的解决了框架部署的服务器对测试报告如何处理的功能设计,我现在实现的效果是:保存最近3个月每个月最近10次测试结果,超过3个月后自动删除测试报告目录并重新创建,框架投入生产使用后,不用手动去处理测试报告文件了。

这个功能实现的源码如下:

import os


class DelReport:
    """删除report目录下历史执行报告文件"""

    def __init__(self):
        self.reportfiles = os.path.join(os.path.dirname(os.path.dirname(__file__)), "report")
        if not os.path.exists(self.reportfiles):
            os.mkdir(self.reportfiles)

    def delete_dirs(self):
        """删除文件夹下所有的文件和子目录"""
        for root, dirs, files in os.walk(self.reportfiles):
            for name in files:
                file_path = os.path.join(root, name)
                if os.path.exists(file_path):
                    try:
                        os.remove(file_path)
                    except:
                        pass

            for name in dirs:
                dir_path = os.path.join(root, name)
                if os.path.exists(dir_path):
                    try:
                        os.rmdir(dir_path)
                    except:
                        pass

        # 如果只是想删除path下的文件和文件夹,保留path,就把下面的代码注释掉
        # if os.path.exists(path):
        #     try:
        #         os.rmdir(path)
        #     except:
        #         delete_dirs(path)

    def Folder_count(self):
        count = 0
        for file in os.listdir(self.reportfiles):
            file = os.path.join(self.reportfiles, file)
            if os.path.isdir(file):  # 判断文件是否可以被打开
                count = count + 1
        return count

    def del_reportfiles(self):
        c = self.Folder_count()
        if c > 3:  # 报告处理时长,3个月
            for i in range(2):  # 先删除文件,在删除文件夹,所以要删除2次
                self.delete_dirs()

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值