测试工具coverage的高阶使用

news2024/11/16 19:39:53

  在文章Python之单元测试使用的一点心得中,笔者介绍了自己在使用Python测试工具coverge的一点心得,包括:

  1. 使用coverage模块计算代码测试覆盖率
  2. 使用coverage api计算代码测试覆盖率
  3. coverage配置文件的使用
  4. coverage badge的生成

  本文在此基础上,将会介绍coverage的高阶使用,包括:

  • Flask API测试
  • coverage多文件测试
  • coverage的Gitlab CI/CD集成
  • coverage badge生成

  本文中使用coverage的版本均为7.3.0。

Flask API测试

  在unittest测试框架如果对Flask API进行测试时使用HTTP请求,那么将无法得到代码覆盖率。
  我们有如下的示例Flask服务:

# -*- coding: utf-8 -*-
from flask import Flask

app = Flask(__name__)


@app.route('/')
def index():
    return "Hello index"


@app.route('/test')
def test():
    return "Hello test"


if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000, debug=True)

  正确的测试代码如下:

# -*- coding: utf-8 -*-
import unittest

from flask_app import app


class AppTestCase(unittest.TestCase):
    def setUp(self):
        self.ctx = app.app_context()
        self.ctx.push()
        self.client = app.test_client()

    def tearDown(self):
        self.ctx.pop()

    def test_case1(self):
        response = self.client.get("/")
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.text, "Hello index")

    def test_case2(self):
        response = self.client.get("/test")
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.text, "Hello test")


if __name__ == "__main__":
    suite = unittest.TestSuite()
    suite.addTest(AppTestCase('test_case1'))
    suite.addTest(AppTestCase('test_case2'))
    run = unittest.TextTestRunner()
    run.run(suite)

coverage多文件测试

  我们有如下的实现两个变量相加的代码(func_add.py):

# -*- coding: utf-8 -*-
def add(a, b):
    if isinstance(a, str) and isinstance(b, str):
        return a + '+' + b
    elif isinstance(a, list) and isinstance(b, list):
        return a + b
    elif isinstance(a, (int, float)) and isinstance(b, (int, float)):
        return a + b
    else:
        return None

  两个测试文件test_func_add1.pytest_func_add2.py,内容如下:

# -*- coding: utf-8 -*-
import unittest

from func_add import add


class TestAdd(unittest.TestCase):
    def setUp(self):
        pass

    def test_add_case1(self):
        a = "Hello"
        b = "World"
        res = add(a, b)
        print(res)
        self.assertEqual(res, "Hello+World")

    def test_add_case2(self):
        a = 1
        b = 2
        res = add(a, b)
        print(res)
        self.assertEqual(res, 3)


if __name__ == '__main__':

    # 部分用例测试
    # 构造一个容器用来存放我们的测试用例
    suite = unittest.TestSuite()
    # 添加类中的测试用例
    suite.addTest(TestAdd('test_add_case1'))
    suite.addTest(TestAdd('test_add_case2'))
    run = unittest.TextTestRunner()
    run.run(suite)
# -*- coding: utf-8 -*-
import unittest

from func_add import add


class TestAdd(unittest.TestCase):
    def setUp(self):
        pass

    def test_add_case3(self):
        a = [1, 2]
        b = [3]
        res = add(a, b)
        print(res)
        self.assertEqual(res, [1, 2, 3])

    def test_add_case4(self):
        a = 2
        b = "3"
        res = add(a, b)
        print(None)
        self.assertEqual(res, None)


if __name__ == '__main__':

    # 部分用例测试
    # 构造一个容器用来存放我们的测试用例
    suite = unittest.TestSuite()
    # 添加类中的测试用例
    suite.addTest(TestAdd('test_add_case3'))
    suite.addTest(TestAdd('test_add_case4'))
    run = unittest.TextTestRunner()
    run.run(suite)

使用命令进行测试:

coverage run test_func_add1.py
coverage run test_func_add2.py
coverage report

生成的代码测试覆盖率如下:

Name          Stmts   Miss  Cover
---------------------------------
func_add.py       8      2    75%
---------------------------------
TOTAL             8      2    75%

这是不符合我们预期的,因为在这两个测试文件中我们对所有的代码都进行了测试,理论上测试覆盖率应该为100%,之所以这样,是因为coverage run命令运行时每一次都会覆盖掉之前的测试。正确的测试命令(以文件追加的形式)如下:

coverage run test_func_add1.py
coverage run --append test_func_add2.py
coverage report

此时代码覆盖率如下:

Name          Stmts   Miss  Cover
---------------------------------
func_add.py       8      0   100%
---------------------------------
TOTAL             8      0   100%

coverage的Gitlab CI/CD集成

  在文章Gitlab CI/CD入门(一)Python项目的CI演示中,笔者介绍了Gitlab CI/CD的入门。在此基础上,我们将集成coverage。
  首先我们的test目录如下:

.
├── __init__.py
├── func_add.py
└── test_func_add.py

func_add.py为实现两个变量相加的代码,如前述。test_func_add.py为测试代码,如下:

# -*- coding: utf-8 -*-
import unittest

from func_add import add


class TestAdd(unittest.TestCase):
    def setUp(self):
        pass

    def test_add_case1(self):
        a = "Hello"
        b = "World"
        res = add(a, b)
        print(res)
        self.assertEqual(res, "Hello+World")

    def test_add_case2(self):
        a = 1
        b = 2
        res = add(a, b)
        print(res)
        self.assertEqual(res, 3)

    def test_add_case3(self):
        a = [1, 2]
        b = [3]
        res = add(a, b)
        print(res)
        self.assertEqual(res, [1, 2, 3])

    def test_add_case4(self):
        a = 2
        b = "3"
        res = add(a, b)
        print(None)
        self.assertEqual(res, None)


if __name__ == '__main__':

    # 部分用例测试
    # 构造一个容器用来存放我们的测试用例
    suite = unittest.TestSuite()
    # 添加类中的测试用例
    suite.addTest(TestAdd('test_add_case1'))
    suite.addTest(TestAdd('test_add_case2'))
    suite.addTest(TestAdd('test_add_case3'))
    suite.addTest(TestAdd('test_add_case4'))
    run = unittest.TextTestRunner()
    run.run(suite)

CI/CD依赖.gitlab-ci.yml,配置如下:

stages:
  - build
  - unittest

build-job:
  stage: build
  script:
    - echo `date`
    - echo "Hello, $GITLAB_USER_LOGIN!"
    - echo "This job deploys something from the $CI_COMMIT_BRANCH branch."

unit_test_job:
  stage: unittest
  image: python:3.9-alpine3.17
  script:
    - pip3 install coverage==7.3.0
    - coverage run test/test_func_add.py
    - coverage report
  coverage: '/TOTAL.*\s+(\d+%)$/'

  运行CI/CD,结果如下图:
unittest_job运行结果
  在Gitlab项目中的Settings -> CI/CD -> General pipelines中点击Expand,会显示CI/CD已内置Pipeline status, Coverage report, Latest release,其中Coverage repor如下图:
Coverage report
  最后我们要在项目中加入coverage badge(徽章),在Gitlab项目中的Settings -> General -> Badge中点击Expand,再点击Add badge,coverage徽章的配置如下:
Add badge
本项目中只有main分支,因此不需要设置变量,实际在使用过程中,需要配置变量如default_branch等。
  以上配置完毕后,项目徽章显示如下:

成功加入徽章!
  以上配置过程已开源,项目网址为:https://gitlab.com/jclian91/gitlab_ci_test 。

coverage badge生成

  coverage badge生成方式分为静态和动态。
  动态的话,可使用coverage-badge或者genbadge模块。
  静态的话,可使用网站:https://shields.io/badges/static-badge .
  比如我们生成编程语言的徽章,如下图:
示例徽章生成
之后我们就可以用该网址访问徽章了。

总结

  本文介绍了测试工具coverage的高阶使用,希望能对读者有所启发~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/899817.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Jmeter生成可视化的HTML测试报告

Jmeter也是可以生成测试报告的。 性能测试工具Jmeter由于其体积小、使用方便、学习成本低等原因,在现在的性能测试过程中,使用率越来越高,但其本身也有一定的缺点,比如提供的测试结果可视化做的很一般。 不过从3.0版本开始&…

【流程引擎】---springboot+camunda案例之费用审批流程

目录 一、案例说明二、案例说明2.1、主要代码实现2.2、案例测试分析过程2.3、总结一、案例说明 上篇文章介绍了springboot简单集成Camunda,后续以具体案例来介绍Camunda使用。 下面介绍一种简单的“费用审批流程”。该流程会串行的经历三层组织审核,一直到流程结束。 其中,…

xollam后缀勒索病毒|勒索病毒解密恢复|xollam勒索病毒专杀|勒索病毒解密|数据库恢复

目录: xollam勒索病毒介绍感染xollam勒索病毒后的表现xollam勒索病毒的感染形式如何恢复.xollam后缀勒索病毒xollam勒索病毒日常防护建议 简介:案例 山东某有限公司的办公系统,由于工作人员在某破解版软件平台下载软件时,不小心点…

PaddleRS 1.0.0版本安装

PaddleRS 1.0.0版本安装 PaddleRS是百度飞桨、遥感科研院所及相关高校共同开发的基于飞桨的遥感影像智能解译开发套件, 支持图像分割、目标检测、场景分类、变化检测、图像复原等常见遥感任务。 PaddleRS致力于帮助遥感领域科研从业者快速完成算法的研发、验证和调…

基于深度学习的铁路异物侵限检测算法研究_整体认知感觉欠点意思,但是有一个新的变形卷积-Octave 卷积

相比于其他的交通运输方式,铁路运输具有准时性高、连续性强、速度快、运输量大、运输成本低以及安全可靠等优点。同时由于国家高速铁路网络建设的不断推进,铁路运输逐渐成为我国客运与货运的主要运输方式。虽然铁路运输为人们出行和货物运输带来的极大的…

Vulnhub系列靶机 Hackadmeic.RTB1

系列:Hackademic(此系列共2台) 难度:初级 信息收集 主机发现 netdiscover -r 192.168.80.0/24端口扫描 nmap -A -p- 192.168.80.143访问80端口 使用指纹识别插件查看是WordPress 根据首页显示的内容,点击target 点击…

【前端面试】中大文件上传/下载:中等文件代理服务器放行+大文件切片传输+并发请求+localstorage实现断点续传

目录 中等文件代理服务器放行:10MB为单位 proxy nginx 大文件切片:100MB为单位 断点:存储切片hash 前端方案A localstorage 后端方案B 服务端 上传 前端 后端 下载 前端 后端 多个大文件传输:spark-md5 哈希碰撞…

002-Nacos 简单集群模式源码解析

目录 介绍架构分析添加实例-同步信息给其他集群服务添加实例-提交同步任务添加实例-执行同步任务实例健康状态监控 介绍 Nacos 启动默认会使用集群模式,也就是没有带有-m standalone 的时候就是用的简单集群模式 另外我们再分析单机模式注册实例的时候最后一部分是把…

【王道-绪论】

#pic_center R 1 R_1 R1​ R 2 R^2 R2 目录 知识框架No.1 操作系统的概念功能和定义一、操作系统的概念和定义二、操作系统的功能和目标1、资源的管理者2、向用户提供服务2.1图形化用户接口2.2联机命令接口2.3脱机命令接口2.4程序接口 3、对硬件机器的拓展 三、总结 No.2 操作系…

Spring Cloud 系列之OpenFeign:(7)链路追踪zipkin

传送门 Spring Cloud Alibaba系列之nacos:(1)安装 Spring Cloud Alibaba系列之nacos:(2)单机模式支持mysql Spring Cloud Alibaba系列之nacos:(3)服务注册发现 Spring Cloud 系列之OpenFeign:(4)集成OpenFeign Spring Cloud …

第三章内存管理

1.内存的基础知识 内存可存放数据。程序执行前需要先放到内存中才能被CPU处理――缓和CPU与硬盘之间的速度矛盾 指令中的地址参数直接给出了变量x的实际存放地址(物理地址) 1.绝对装入 绝对装入:在编译时,如果知道程序将放到内存中的哪个位置,编译程序将…

springboot+Vue--打基础升级--(二)写个主菜单导航界面

1. 华为OD机考题 答案 2023华为OD统一考试(AB卷)题库清单-带答案(持续更新) 2023年华为OD真题机考题库大全-带答案(持续更新) 2. 面试题 一手真实java面试题:2023年各大公司java面试真题汇总--…

ansible(2)-- ansible常用模块

部署ansible:ansible(1)-- 部署ansible连接被控端_luo_guibin的博客-CSDN博客 目录 一、ansible常用模块 1.1 ping 1.2 command 1.3 raw 1.4 shell 1.5 script 1.6 copy 1.7 template 1.8 yum 11.0.1.13 主控端(ansible)11.0.1.12 被控端(k8s…

K8S deployment挂载

挂载到emptyDir 挂载在如下目录,此目录是pod所在的node节点主机的目录,此目录下的data即对应容器里的/usr/share/nginx/html,实现目录挂载 apiVersion: apps/v1 kind: Deployment metadata:annotations:deployment.kubernetes.io/revision: …

Qt实现简单的漫游器

文章目录 Qt的OpenGL窗口GLSL的实现摄像机类的实现简单的漫游器 Qt的OpenGL窗口 Qt主要是使用QOpenGLWidget来实现opengl的功能。  QOpenGLWidget 提供了三个便捷的虚函数,可以重载,用来重新实现典型的OpenGL任务: paintGL:渲染…

零基础入门网络安全,收藏这篇不迷茫【2023最新】

前言 最近收到不少关注朋友的私信和留言,大多数都是零基础小友入门网络安全,需要相关资源学习。其实看过的铁粉都知道,之前的文里是有过推荐过的。新来的小友可能不太清楚,这里就系统地叙述一遍。 01.简单了解一下网络安全 说白…

【ARM Linux 系统稳定性分析入门及渐进12 -- GDB内存查看命令 “x“(examine)】

文章目录 gdb 内存查看命令 examine 上篇文章:ARM Linux 系统稳定性分析入门及渐进11 – GDB( print 和 p 的使用| 和 ::的使用|ptype|{<type>} <addr> ) gdb 内存查看命令 examine examine是…

【C# 基础精讲】LINQ 基础

LINQ(Language Integrated Query)是一项强大的C#语言特性,它使数据查询和操作变得更加简洁、灵活和可读性强。通过使用LINQ,您可以使用类似SQL的语法来查询各种数据源,如集合、数组、数据库等。本文将介绍LINQ的基础概…

Kvm配置ovs网桥

环境:部署在kvm虚拟环境上(让虚拟机和宿主机都可以直接从路由器获取到独立ip) 1、安装ovs软件安装包并启动服务(一般采用源码安装,此处用yum安装) yum install openvswitch-2.9.0-3.el7.x86_64.rpm syste…

UVC摄像头

1 版本历史 1.1 UVC uvc_version UVC 1.0: Sep-4-2003 UVC 1.1: Jun-1-2005 UVC 1.5: August-9-2012, H.264 video codec. Linux 4.5 introduces UVC 1.5, but does not support H264. 1.2 V4L版本历史 Video4Linux取名的灵感来自1992 Video for Windows(V4W&#x…