测试工具coverage的高阶使用

  在文章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 Flaskapp = 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 unittestfrom flask_app import appclass 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 + '+' + belif isinstance(a, list) and isinstance(b, list):return a + belif isinstance(a, (int, float)) and isinstance(b, (int, float)):return a + belse:return None

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

# -*- coding: utf-8 -*-
import unittestfrom func_add import addclass TestAdd(unittest.TestCase):def setUp(self):passdef 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 = 1b = 2res = 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 unittestfrom func_add import addclass TestAdd(unittest.TestCase):def setUp(self):passdef 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 = 2b = "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 unittestfrom func_add import addclass TestAdd(unittest.TestCase):def setUp(self):passdef 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 = 1b = 2res = 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 = 2b = "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- unittestbuild-job:stage: buildscript:- echo `date`- echo "Hello, $GITLAB_USER_LOGIN!"- echo "This job deploys something from the $CI_COMMIT_BRANCH branch."unit_test_job:stage: unittestimage: python:3.9-alpine3.17script:- pip3 install coverage==7.3.0- coverage run test/test_func_add.py- coverage reportcoverage: '/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.mzph.cn/news/49601.shtml

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

相关文章

【Android】设置-显示-屏保-启用时机-去除插入基座相关(不支持该功能的话)

设置-显示-屏保-启用时机-去除插入基座相关(不支持该功能的话) 1-项目场景:2-问题描述3-解决方案:4-代码修改前后效果对比图:代码修改前:代码修改后: 1-项目场景: 展锐平台 2-问题描…

ctfshow-web12

0x00 前言 CTF 加解密合集CTF Web合集 0x01 题目 0x02 Write Up 国际惯例看一下返回包,是不是有注释 然后做一下测试,看是命令执行还是代码执行 通过phpinfo看到可以执行代码 然后尝试执行命令,无法,发现存在disable_function…

optee读取Arm系统寄存器的模板

先写一个通用的内联函数模板,然后再通过宏控来定义各种读写函数。 (core/arch/arm/include/arm64.h)/** Templates for register read/write functions based on mrs/msr*/#define DEFINE_REG_READ_FUNC_(reg, type, asmreg) \ sta

Struct和union的理解

结构体(struct)和共用体(union)都是用于组合多个不同类型的数据成员,但它们在内存存储方式和数据访问方式上存在差异。以下是结构体和共用体之间的主要区别: 结构体(struct)&#x…

基于nginx禁用访问ip

一、背景 网络安全防护时,禁用部分访问ip,基于nginx可快速简单实现禁用。 二、操作 1、创建 conf.d文件夹 在nginx conf 目录下创建conf.d文件夹 Nginx 扩展配置文件一般在conf.d mkdir conf.d 2、新建blocksip.conf文件 在conf.d目录新建禁用ip的扩展配置文…

(一)Docker简介(一篇足以)

一、简介 一个项目环境配置相当麻烦,如果换一台机器跑起来,所有配置就要重来一次,费力费时。很多人想到,能不能从根本上解决问题,软件可以带环境安装?也就是说,安装的时候,把原始环…

scala array类型参数

在Scala中,数组(Array)是一种用于存储相同类型元素的数据结构。数组可以用于保存基本数据类型和自定义数据类型的元素。当定义数组类型参数时,您通常是在函数、类或方法签名中使用它们。以下是一些有关Scala数组类型参数的示例&am…

从头到尾说一次 Spring 事务管理(器) | 京东云技术团队

事务管理,一个被说烂的也被看烂的话题,还是八股文中的基础股之一。​ 本文会从设计角度,一步步的剖析 Spring 事务管理的设计思路(都会设计事务管理器了,还能玩不转?) 为什么需要事务管理&…

C++基础Ⅰ编译、链接

目录儿 1 C是如何工作的1.1 预处理语句1.2 include1.3 main()1.4 编译单独编译项目编译 1.5 链接 2 定义和调用函数3 编译器如何工作3.1 编译3.1.1 引入头文件系统头文件自定义头文件 3.1.2 自定义类型3.1.3 条件判断拓展: 汇编 3.2 链接3.2.1 起始函数3.2.2 被调用的函数 3.3 …

无人机精细化巡检方案制定:提高效率与准确性的关键

在当前技术日新月异的时代,无人机在多个领域的应用已成为行业标配。但如何制定出一套有效、细致的无人机巡检方案,确保其最大效能,成为许多组织与公司的核心议题。其中,复亚智能在此领域已展现出了卓越的实力与深入的见解。 1. 精…

把matlab的m文件打包成单独的可执行文件

安装Matlab Compiler Adds-on在app里找到Application Compiler 选择要打包的文件matlab单独的运行程序的话需要把依赖的库做成runtime. 这里有两个选项. 上面那个是需要对方在联网的情况下安装, 安装包较小.下面那个是直接把runtime打包成安装程序, 大概由你的程序依赖的库的多…

游乐场vr设备虚拟游乐园vr项目沉浸体验馆

在景区建设一个VR游乐场项目可以为游客提供一种新颖、刺激和沉浸式的游乐体验。提高游客的体验类型,以及景区的类目,从而可以吸引更多的人来体验。 1、市场调研:在决定建设VR游乐场项目之前,需要进行市场调研,了解当地…

ip地址和地理位置有关系吗

在互联网时代,网络已经成为了人们生活中不可或缺的一部分。而在网络通信中,IP地址扮演着非常重要的角色。那么,IP地址和地理位置之间是否有关系呢?虎观代理小二二将从以下几个方面进行探讨。 一、IP地址和地理位置的基本概念 首…

k8s发布应用

前言 首先以SpringBoot应用为例介绍一下k8s的发布步骤。 1.从代码仓库下载代码,比如GitLab; 2.接着是进行打包,比如使用Maven; 3.编写Dockerfile文件,把步骤2产生的包制作成镜像; 4.上传步骤3的镜像到…

深入浅出Pytorch函数——torch.nn.init.eye_

分类目录:《深入浅出Pytorch函数》总目录 相关文章: 深入浅出Pytorch函数——torch.nn.init.calculate_gain 深入浅出Pytorch函数——torch.nn.init.uniform_ 深入浅出Pytorch函数——torch.nn.init.normal_ 深入浅出Pytorch函数——torch.nn.init.c…

DNQ算法原理(Deep Q Network)

1.强化学习概念 学习系统没有像很多其它形式的机器学习方法一样被告知应该做出什么行为 必须在尝试了之后才能发现哪些行为会导致奖励的最大化 当前的行为可能不仅仅会影响即时奖励,还会影响下一步的奖励以及后续的所有奖励 每一个动作(action)都能影响代理将来的…

C++的初步介绍,以及C++与C的区别

C和C的区别 C又称C plus plus,且C语言是对C语言的扩充,几乎支持所有的C语言语法;C语言:面向过程的语言(注重问题的解决方法和算法)C:面向对象的语言 (求解的方法)面向对…

linux 上安装es

首先 到官网 https://www.elastic.co/cn/downloads/elasticsearch 下载对应的安装包,我这里下载的是 https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.9.1-linux-x86_64.tar.gz 然后讲该压缩包上传到 linux 的/usr/local 目录下执行 tar -z…

Just KNIME it[S2C21] 图像识别

朋友们,Just KNIME it 还有在跟进吗? 本季已经到 21 期啦。 本期探讨的主题是图像识别问题,快随指北君一起看看吧。 挑战 21:帮助球童(第 1 部分) 级别:中 描述:球童汤姆是一位最受欢迎的高尔夫…

Ansible学习笔记(一)

1.什么是Ansible 官方网站:https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html Ansible是一个配置管理和配置工具,类似于Chef,Puppet或Salt。这是一款很简单也很容易入门的部署工具,它使用SS…