Django(10)-项目实战-对发布会管理系统进行测试并获取测试覆盖率

news2024/11/17 17:54:49

在发布会签到系统中使用django开发了发布会签到系统,
本文对该系统进行测试。

django.test

django.test是Django框架中的一个模块,提供了用于编写和运行测试的工具和类。

django.test模块包含了一些用于测试的类和函数,如:

  • TestCase:这是一个基类,用于编写Django测试用例。继承自unittest.TestCase,提供了一些额外的功能和方法,用于处理Django应用程序的测试环境。

  • SimpleTestCase:这是一个更轻量级的测试基类,适用于没有数据库或网络访问的简单测试场景。

  • Client:这是一个模拟HTTP请求的客户端类,用于在测试中模拟用户请求和验证响应结果。

  • RequestFactory:这是一个用于创建HTTP请求对象的工厂类,用于在测试中生成HTTP请求实例。

  • 其他辅助函数和装饰器,如override_settings用于在测试过程中临时覆盖Django设置,tag用于给测试用例添加标签等。

通过使用django.test模块,你可以编写单元测试、集成测试和功能测试等来验证和确保Django应用程序的正确性和稳定性。

下面是一个简单的示例代码,演示如何使用django.test模块编写一个测试用例类:

from django.test import TestCase

class MyTestCase(TestCase):
    def test_my_function(self):
        # 编写测试逻辑
        result = my_function()
        self.assertEqual(result, expected_result)

总结来说,django.test模块提供了一套用于编写和运行Django应用程序测试的工具和类,能够帮助开发者验证和确保应用程序的正确性和稳定性。

测试index视图

在这里插入图片描述

import os,django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "guest.settings")
import django
django.setup()
from django.test import TestCase
class IndexPageTest(TestCase):
    def test_index_page_renders_index_template(self):
        response = self.client.get("/index/")
        self.assertEqual(response.status_code,200)
        self.assertTemplateUsed(response,'index.html')

测试类徐亚集成TestCase,使用client实例可以请求get和post HTTP请求
获取response后断言状态码,
并使用assertTemplateUsed方法断言该请求是否使用index.html模板

测试login视图

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "guest.settings")


from django.contrib.auth.models import User
from django.test import TestCase
class LoginActionTest(TestCase):

    def setUp(self) -> None:
        User.objects.create_user("admin1","admin@mail.com","admin123456") #创建用户
    def test_add_admin(self):
        user=User.objects.get(username="admin1")#查询
        self.assertEqual(user.username,"admin1")
        self.assertEqual(user.email, "admin@mail.com")
    def test_login_action_username_password_null(self):
        """测试密码为空"""
        test_data={'username':'','password':''}
        response=self.client.post('/login/',data=test_data) #使用self的client可以对urls进行测试
        self.assertEqual(response.status_code,200)
        self.assertIn(b"username or password error",response.content)
    def test_error_password(self):
        test_data = {'username': 'abc', 'password': ''}
        response = self.client.post('/login/', data=test_data)  # 使用self的client可以对urls进行测试
        self.assertEqual(response.status_code, 200)
        self.assertIn(b"username or password error", response.content)
    def test_login_success(self):
        test_data = {'username': 'admin', 'password':'admin123456'}
        response = self.client.post('/login/', data=test_data)  # 使用self的client可以对urls进行测试
        self.assertEqual(response.status_code, 302)


在第一个测试方法中对User进行了测试,查询数据库是否新建了该账号
在2,3,4测试方法里则是测试了/login/请求,通过传入不同的参数,校验响应。

注意b:在Python中,字符串前面加上b表示这是一个字节字符串(bytes string)。字节字符串是一种以字节为单位表示的字符串,它可以包含任意的二进制数据。

在上述代码中,response.content被认为是一个字节字符串。将b"username or password error"作为参数传递给elf.assertIn()函数,表示期望的"username or password error"字符串是以字节的形式存在的。

使用字节字符串的一个常见场景是在进行文本匹配或者通过网络传输二进制数据时,通常需要使用字节字符串来处理二进制数据以及非ASCII字符集。

与之相对,普通的字符串(字符字符串)在Python中使用引号括起来,例如"username or password error"。它们是以Unicode字符为单位表示的字符串,适用于大多数文本处理任务。

需要注意的是,对于编写测试用例来说,根据实际情况选择使用字节字符串或字符字符串,确保与被测试代码中的数据类型一致。

测试模型


from datetime import datetime
import os,django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "guest.settings")# project_name 项目名称
django.setup()
from django.test import TestCase
from sign.models import Event,Guest

from django.test.utils import setup_test_environment
setup_test_environment()
time=datetime.now()
class ModelTest(TestCase):
    def setUp(self) -> None:

        Event.objects.create(id=4,name="oneplus 3 event",status=True,limit=2000,address="shenzhen",start_time=time)
        Guest.objects.create(id=4, event_id=4,realname="zhangsan",phone="13276766666",email="zhangsan@qq.com",sign=False,
                             create_time=time)
    def test_event_models(self):
        result=Event.objects.get(name="oneplus 3 event")
        self.assertEqual(result.address,"shenzhen")
        self.assertTrue(result.status)

    def test_guest_models(self):
        result=Guest.objects.get(phone="13276766666")
        self.assertEqual(result.realname,"zhangsan")
        self.assertFalse(result.sign)

测试模型时需要先在setup里创建模型,然后在测试方法里调用查询方法校验是否创建成功,

测试event_manage

import os,django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "guest.settings")
django.setup()
from datetime import datetime

from django.contrib.auth.models import User

from sign.models import Event
time=datetime.now()


import django
django.setup()
from django.test import TestCase
class EventManageTest(TestCase):
    def setUp(self) -> None:
        """测试event_manage和搜索方法,需要先登录,所以在setup里先登录"""
        User.objects.create_user("admin1", "admin@mail.com", "admin123456")
        test_data = {'username': 'admin', 'password': 'admin123456'}
        response = self.client.post('/login/', data=test_data)
        Event.objects.create(id=4, name="oneplus 3 event", status=True, limit=2000, address="shenzhen", start_time=time)


    def test_event(self):
        response = self.client.get("/event_manage/")
        self.assertEqual(response.status_code, 200)
        self.assertIn(b"oneplus", response.content) #response.content
        self.assertIn(b"shenzhen", response.content)
    def test_search(self):
        """测试搜索"""
        testdata={"search_name":"oneplus"}
        response = self.client.get("/search_name/",data=testdata)
        self.assertEqual(response.status_code, 200)
        self.assertIn(b"oneplus", response.content) #response.content
        self.assertIn(b"shenzhen", response.content)

因为event_manage请求在登录后才能调用,所以在setup里请求了登录接口。
在测试方法里调用了对应接口,并校验结果。

测试签到功能

import os,django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "guest.settings")
django.setup()
from datetime import datetime

from django.contrib.auth.models import User

from sign.models import Event, Guest

time=datetime.now()


import django
django.setup()
from django.test import TestCase
class SignTest(TestCase):
    def setUp(self) -> None:
        """测试event_manage和搜索方法,需要先登录,所以在setup里先登录"""
        User.objects.create_user("admin1", "admin@mail.com", "admin123456")
        test_data = {'username': 'admin', 'password': 'admin123456'}
        response = self.client.post('/login/', data=test_data)
        Event.objects.create(id=5, name="oneplus 3 event", status=True, limit=2000, address="shenzhen", start_time=time)
        Event.objects.create(id=4, name="oneplus 3 event", status=True, limit=2000, address="shenzhen", start_time=time)
        # Event.objects.create(id=4, name="oneplus 3 event", status=True, limit=2000, address="shenzhen", start_time=time)

        Guest.objects.create(id=4, event_id=4, realname="lisi", phone="13276766666", email="lisi@qq.com",
                         sign=False,
                         create_time=time)
        Guest.objects.create(id=5, event_id=5, realname="lisi", phone="13276609878", email="lisi@qq.com",
                             sign=True,
                             create_time=time)
    def test_sign_1(self):
        response = self.client.get("/sign_index/4/")
        print(response.content)
        self.assertEqual(response.status_code, 200)
        self.assertIn(b"oneplus 3 event", response.content) #response.content

    def test_sign_phone_error(self):
        response = self.client.post("/sign_index_action/4/",{"phone":"1321761766666"})
        self.assertEqual(response.status_code, 200)
        self.assertIn(b"phone error", response.content) #response.content
    def test_sign_phone_not_match(self):
        response = self.client.post("/sign_index_action/4/",{"phone":"13276609878"})
        self.assertEqual(response.status_code, 200)
        self.assertIn(b"event id or phone error", response.content) #response.content
    def test_sign_phone_success(self):
        response = self.client.post("/sign_index_action/4/",{"phone":"13276766666"})
        self.assertEqual(response.status_code, 200)
        self.assertIn(b"sign in success", response.content) #response.content
    def test_sign_phone_has_sign(self):
        response = self.client.post("/sign_index_action/5/",{"phone":"13276609878"})
        self.assertEqual(response.status_code, 200)
        self.assertIn(b"user has sign in", response.content) #response.content

因为签到功能需要先有发布会和客户,所以需要在setup里先创建对应模型,然后在测试方法中传入不同的参数,校验结果。
可以看到使用django.test进行测试,即测试了网页路由,也测试了对应的视图函数。

测试数据库

在Django中,当你运行测试用例时,测试框架会自动为你创建一个专用的测试数据库,该数据库是在测试运行期间被使用的临时数据库。当测试完成后,测试框架会清除该数据库。

在进行模型测试时,如果你在测试用例中创建了模型实例并保存到数据库中,测试框架会确实在测试数据库中创建相应的表以及保存模型对象的记录。

示例代码:

from django.test import TestCase
from myapp.models import MyModel

class ModelTestCase(TestCase):
    def test_create_model(self):
        # 创建并保存模型对象
        MyModel.objects.create(name="Example")

        # 断言模型对象是否在测试数据库中存在
        self.assertTrue(MyModel.objects.exists())

当你运行上述测试用例时,测试框架会在测试数据库中创建一个MyModel表,并将模型对象保存在该表中。注意,测试中的模型数据不会影响你的开发或生产环境数据库,它们只是在测试期间使用的临时数据。

需要注意的是,测试数据库是独立于你的开发或生产数据库的,并且在每次运行测试时都会自动创建和销毁。这样可以确保测试的可靠性和独立性。
在这里插入图片描述
如图,在运行发布会测试文件时,显示创建了数据库,在测试结束时,数据库被销毁。
所以在进行测试时,用户和数据库表等信息,都需要创建。
如果在运行测试,发现状态码返回是302,需要注意是否创建用户,并使用该用户登录。

运行测试

python manage.py test tests
可以使用tests目录下的所有测试文件
在这里插入图片描述
可以看到运行了16个用例都通过了

测试覆盖率

测试覆盖率是一种度量软件测试程度的指标,它衡量了测试代码中有多少部分被执行了。

要计算测试覆盖率,可以使用以下公式:

测试覆盖率 = (已执行的代码行数 / 总代码行数) * 100

具体的计算步骤可以分为以下几个步骤:

  1. 确定要计算覆盖率的代码范围。这可以是整个项目、单个文件、单个函数等。

  2. 运行测试套件。执行针对代码范围的测试,确保已经执行了尽可能多的代码路径。

  3. 收集执行信息。使用测试覆盖率工具(如 coverage)来跟踪代码的执行情况,并记录已经执行的代码行。

  4. 统计覆盖率数据。根据执行信息统计已经执行的代码行数和总代码行数。

  5. 计算覆盖率百分比。根据统计的数据,使用上述公式计算测试覆盖率百分比。

测试覆盖率可以根据需要进行细分,如语句覆盖率(Statement Coverage)、分支覆盖率(Branch Coverage)、条件覆盖率(Condition Coverage)等。具体的计算方式和度量指标可能会有所不同,但基本原理是相似的。

需要注意的是,测试覆盖率并不能完全衡量代码的质量,它只能指示测试是否已经覆盖了一定程度的代码。在计算测试覆盖率时,应该根据项目的实际情况和需求来确定合适的目标和阈值。

总结来说,测试覆盖率是通过统计已执行的代码行数与总代码行数之比来计算的。使用测试覆盖率工具可以帮助收集和分析执行信息,从而得出测试覆盖率的百分比。测试覆盖率可以帮助评估测试的完整程度,但它并不能完全代表代码的质量。

coverage获取测试覆盖率

在Python中,你可以使用第三方库 coverage 来获取测试覆盖率数据。coverage 是一个广泛使用的代码覆盖率工具,可以统计你的测试用例对代码的覆盖情况。

下面是一个简单的示例,展示了如何使用 coverage 来获取测试覆盖率数据:

  1. 安装 coverage 库:

    pip install coverage
    
  2. 在终端中运行测试并收集覆盖率数据:

    
    

    这里 myapp 是你要测试的应用程序的名称。--source 参数用于指定要收集覆盖率数据的代码路径。

  3. 生成覆盖率报告:

    coverage report
    

    运行该命令后,coverage 将会产生一个简单的文本报告,显示每个文件和每个文件中被测试的代码行的覆盖情况。

你也可以使用 coverage html 命令生成一个 HTML 格式的覆盖率报告,该报告能够更直观地展示代码覆盖情况。

注意:在运行测试之前,确保你的代码已经被正确安装和配置,并且拥有相应的测试用例。

总结来说,通过使用 coverage 库,你可以轻松地获取你的Python代码的测试覆盖率数据,并生成相应的报告来帮助你分析和评估你的测试质量。
在这里插入图片描述

运行coverage

coverage run --source=sign manage.py test
这里–source后面是目录,意思是统计sign目录下文件的代码执行覆盖率,即sign下每个文件里的代码在执行时运行了几行。
在这里插入图片描述
在这里插入图片描述
可以看到,apps里代码一共3行,miss 3行,说明3行代码都没有执行到,
总的测试覆盖率是95%,也就是代码行覆盖率是95%

也可以不指定目录,则会计算根路径下所有文件代码执行覆盖率。
coverage run manage.py test
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

【算法奥义】最大矩形问题

首先建立一个二维数组,这个二维数组,计算出矩阵的每个元素的左边连续 1 的数量,使用二维数组 left记录,其中left[i][j] 为矩阵第 i 行第 j 列元素的左边连续 1 的数量。 也就是从这个元素开始,从右往左边数有多少个连…

一年一度的苹果秋季发布会7个重要议题需回答,看是否有你关心的

当苹果公司举行产品发布会,比如即将于9月12日举行的苹果活动时,这无疑是该公司向我们介绍其最终展示的产品的来龙去脉的机会。但这也是苹果回答一些紧迫问题的机会,不仅是关于其最新的iPhone、Apple Watch和平板电脑,还有关于其作为一家公司的发展方向。 我们将在9月12日的…

iMazing2024绿色版iOS手机备份软件

乍一看,编辑iPhone或iPad的备份似乎是一个奇怪的命题,但实际上这样做的原因有很多,例如在备份数据损坏时进行修复,又如合并来自不同设备的数据。 iMazing对备份文件编辑的支持非常全面,即使备份是加密的、或是横跨不同…

SVN基本使用笔记——广州云科

简介 SVN是什么? 代码版本管理工具 它能记住你每次的修改 查看所有的修改记录 恢复到任何历史版本 恢复己经删除的文件 SVN跟Git比,有什么优势 使用简单,上手快 目录级权限控制,企业安全必备 子目录Checkout,减少不必要的文件检出…

【UIPickerView案例02-点餐显示数据默认选中 Objective-C语言】

一、这个显示数据 1.它里面,有数据源协议、代理协议、以前,TableView里面,怎么用的, 前面我们是怎么做的, 1)第一步:你是不是设置数据, 设置数据源对象、代理对象、然后呢, 然后呢,咱们Main.storyboard,是不是右键, 把这个数据源对象,拖到控制器上 代理对象,…

Mybatis 动态SQL – 使用if,where标签动态生成条件语句

前面几篇我们介绍了使用Mybatis进行数据的增删改查,并且也了解了如何在Mybatis中使用JDK的日志系统打印日志;本篇我们继续介绍如何使用Mybatis提供的if,where标签动态生成条件语句。 如果您对数据的增删改查和Mybatis集成JDK日志系统不太了解&#xff0…

Mysql锁及行锁机制探索

先讲一下mysql存储方式(innodb) 分为,聚簇索引和非聚簇索引。 聚簇索引,就是b树的所有真实数据。 聚簇索引不是一种索引类型,而是一种数据存储方式。innoDB的聚簇索引实际上在同一个结构中保存了B-Tree索引和数据行。当表有聚簇索引时&…

PlumeLog查不到日志

一 问题: PlumeLog查不到日志,记录遇到的情况 二 场景 1. 输入不全

5款轻量级小软件,突出一个简洁轻便

​ 今天的主题是简洁,轻便,都是轻量级的小软件,界面都是非常简洁,而且无广告的。 1.图形设计——Affinity Designer ​ Affinity Designer是一款获奖的矢量图形软件,它设定了设计界的新标准。它适用于Windows, macOS…

FANUC机器人电气控制柜内部硬件电路和模块详细介绍

FANUC机器人电气控制柜内部硬件电路和模块详细介绍 PSU电源单元 通过背板传输了如下电源 +5 +2.0V +3.3 +24v +24E +15V -15V 主板--接口描述: 主板内部结构: 面板电路板: 引申一下 KM21 与 KM22 的作用它们分别接至操作面板上上的急停按

c++入门一

参考:https://www.learncpp.com/cpp-tutorial/ When you finish, you will not only know how to program in C, you will know how NOT to program in C, which is arguably as important. Tired or unhappy programmers make mistakes, and debugging code tends…

详解mysql事务,事务并发安全问题的复现以及大事务的优化

好文推荐: 2.5万字详解23种设计模式 springboot 实现延时队列(超级实用) 2.5万字讲解DDD领域驱动设计 文章目录 1. 事务定义2. 事务特性(ACID)3. 事务并发问题4. 事务隔离级别5. 基础命令6. 脏读复现7. 不可重复读复现…

滑动窗口实例5(水果成篮)

题目: 你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。 你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按…

qt相关的demo集合

自己写过的qt/c相关程序的demo集合 (许多学习自网络中,很感谢大家的分享) 源码地址:Qt与学习通页面: 记录与Qt相关的代码 - Gitee.com 源码目录: echart简单应用 opencv图像处理 QSetting简单使用 QtAv播放视频 ui页面 表情 超星…

Vue框架--Vue中的数据代理

下面,我们一起来说以下Vue中的数据代理。 1.Object.defineProperty()方法回顾 * Object.defineProperty()方法基本配置项 * value:指定设置对象内容的属性值 * enumerable:true, //控制属性是否可以枚举(也就是是否可以被遍历),默认值是false * writable:true, //控制属性是…

苹果将在iPhone16系列中引入微透镜阵列技术,亮度更高、功耗更低

根据韩国媒体The Elec的报道,苹果公司正与其主要供应商三星和LG展开合作,以评估并衡量是否有必要在明年的iPhone 16系列中引入微透镜(micro-lens)技术来升级屏幕。 这项方案集中在OLED屏幕架构上,计划采用微透镜阵列&…

20用于深度学习训练和研究的数据集

数据集在计算机科学和数据科学中发挥着至关重要的作用。它们用于训练和评估机器学习模型,研究和开发新算法,改进数据质量,解决实际问题,推动科学研究,支持数据可视化,以及决策制定。数据集提供了丰富的信息…

13 mysql date/time/datetime/year 的数据存储

前言 这里主要是 由于之前的一个 datetime 存储的时间 导致的问题的衍生出来的探究 探究的主要内容为 int 类类型的存储, 浮点类类型的存储, char 类类型的存储, blob 类类型的存储, enum/json/set/bit 类类型的存储 本文主要 的相关内容是 datetime/date/time/year 类类型…

RNN 单元:分析 GRU 方程与 LSTM,以及何时选择 RNN 而不是变压器

一、说明 深度学习往往感觉像是在雪山上找到自己的道路。拥有坚实的原则会让你对做出决定更有信心。我们都去过那里 在上一篇文章中,我们彻底介绍并检查了 LSTM 单元的各个方面。有人可能会争辩说,RNN方法已经过时了,研究它们是没有意义的。的…

如何增强客户支持?用全渠道聊天机器人

您的用户在哪里?您是否想拥有源源不断的客户?全渠道聊天机器人可确保您在他们需要的地方为他们提供一致的客户支持! 自技术出现以来,消费者行为已经完全改变。这意味着企业与用户互动和提供客户支持的方式也发生了变化。现在&…