使用 Python 进行测试(7)...until you make it

在这里插入图片描述

总结

我很懒,我想用最少的行动实现目标,例如生成测试数据。我们可以:

使用随机种子保证数据的一致性。

>>> random.seed(769876987698698)
>>> [random.randint(0, 10) for _ in range(10)]
[10, 9, 1, 9, 10, 6, 5, 10, 1, 9]
>>> random.seed(769876987698698)
>>> [random.randint(0, 10) for _ in range(10)]
[10, 9, 1, 9, 10, 6, 5, 10, 1, 9]

使用mimesis生成虚假数据:

>>> from mimesis import Generic
>>> g = Generic()
>>> for _ in range(5):
...     print(
...         f"[{g.datetime.date()}] {g.person.full_name()}, "
...         f"PIN attempt {g.code.pin()} at "
...         f"{g.finance.bank()} ({g.address.city()}) "
...         f"from {g.internet.ip_v4()}"
...     )
[2005-08-20] Rosario Howe, PIN attempt 1155 at Bank of Marin (Solon) from 171.243.230.180
[2001-11-14] Julieann Spencer, PIN attempt 4044 at State Street Corporation (Round Rock) from 155.236.115.163
[2003-07-24] Mikel Buchanan, PIN attempt 1057 at Union Bank (Scarsdale) from 211.192.167.83
[2010-10-30] Antione Duffy, PIN attempt 6219 at Sandy Spring Bancorp (Phoenix) from 207.104.0.29
[2004-06-05] Damon Stephens, PIN attempt 6115 at First National Community Bank (Newport) from 226.230.244.209

使用freezegun冻结时间:

>>> import datetime
... from freezegun import freeze_time
...
... def calendar_with_cheesy_quote():
...     print(f"{datetime.date.today():%B %d, %Y}")
...     print("Each day provide it's own gift")
...
... with freeze_time("2012-01-14"):
...     calendar_with_cheesy_quote()

使用pyfakefs模拟内存中的文件系统:

from pyfakefs.fake_filesystem_unittest import Patcher
from pathlib import Path
import oswith Patcher() as patcher:fs = patcher.fstemp_path = Path(os.path.join(os.sep, 'tmp', 'tempdir'))fs.create_dir(temp_path)(temp_path / 'subdir1').mkdir()(temp_path / 'subdir2').mkdir()(temp_path / 'file1.txt').write_text('This is file 1')(temp_path / 'file2.txt').write_text('This is file 2')print(f'Now you see me: {temp_path}')print(f'Contents: {list(temp_path.iterdir())}')fs.remove_object(temp_path)print(f"Now you don't: {temp_path.exists()}"")

通过VCR.py 记录HTTP调用:

import pytest
import requests@pytest.mark.vcr
def test_single():assert requests.get("http://httpbin.org/get").text == '{"get": true}'

使用inline-snapshot快照测试结果:

from inline_snapshot import snapshotdef test_something():assert 1548 * 18489 == snapshot() # snapshot() is the placeholder

现在是自由活动时间,去操场玩吧!

Less is more。

你可以手动创建伪造的数据,但很麻烦。让我们升级到自动化。

关于seed

许多生成数据的工具都使用seed产生伪随机。
实际上,真正的随机无法通过软件实现,只能通过现实中的随机源实现。但很多时候我们只需要一个无法被别人预测的值。
secrets使用随机性的操作系统源,random使用随机种子产生伪随机。

使用相同的随机种子,会得到同一个值:

>>> random.seed(769876987698698)
>>> [random.randint(0, 10) for _ in range(10)]
[10, 9, 1, 9, 10, 6, 5, 10, 1, 9]
>>> random.seed(769876987698698)
>>> [random.randint(0, 10) for _ in range(10)]
[10, 9, 1, 9, 10, 6, 5, 10, 1, 9]

一般虚假数据

从生成 HTML 填充到填充数据库,伪造数据是一项资产,可用于概念验证、文档,当然还有测试。

memesis 是一个极好的 Python 库,您可以 pip 安装,它可以让您生成成千上万的虚假电子邮件、地址、社会安全号码、颜色、食品和 lorem ipsums。

>>> from mimesis import Generic
>>> g = Generic()
>>> for _ in range(5):
...     print(
...         f"[{g.datetime.date()}] {g.person.full_name()}, "
...         f"PIN attempt {g.code.pin()} at "
...         f"{g.finance.bank()} ({g.address.city()}) "
...         f"from {g.internet.ip_v4()}"
...     )
[2005-08-20] Rosario Howe, PIN attempt 1155 at Bank of Marin (Solon) from 171.243.230.180
[2001-11-14] Julieann Spencer, PIN attempt 4044 at State Street Corporation (Round Rock) from 155.236.115.163
[2003-07-24] Mikel Buchanan, PIN attempt 1057 at Union Bank (Scarsdale) from 211.192.167.83
[2010-10-30] Antione Duffy, PIN attempt 6219 at Sandy Spring Bancorp (Phoenix) from 207.104.0.29
[2004-06-05] Damon Stephens, PIN attempt 6115 at First National Community Bank (Newport) from 226.230.244.209

您甚至可以设置区域设置。例如,如果我想要一些法语数据:

>>> from mimesis.locales import Locale
... g = Generic(locale=Locale.FR)
... for _ in range(5):
...     print(
...         f"[{g.datetime.date()}] {g.person.full_name()}, "
...         f"essai de PIN {g.code.pin()} à "
...         f"{g.finance.bank()} ({g.address.city()}) "
...         f"depuis {g.internet.ip_v4()}"
...     )
...
[2004-02-14] Joana Menard, tentative de PIN 4616 à Neuflize OBC (Colmar) depuis 193.125.166.248
[2012-07-08] Juliet Dastous, tentative de PIN 1168 à Banque de Savoie (Agen) depuis 6.232.176.31
[2018-01-23] Chloé Maurin, tentative de PIN 4101 à LCL (Menton) depuis 142.144.98.158
[2021-03-18] Nabil Jutras, tentative de PIN 6478 à Crédit Mutuel Alliance Fédérale (Bobigny) depuis 58.188.207.52
[2013-03-29] Noam Grand, tentative de PIN 4820 à AXA Banque (Poissy) depuis 186.54.107.131

它甚至可以与日语一起使用,数据集令人印象深刻,并且它已经取代了我工具包中我心爱的faker

我现在在PYTHONSARTUP中使用这个:

PYTHONSARTUP: 设置shell变量的脚本

try:import mimesis
except ImportError:pass
else:from mimesis.locales import Localefrom mimesis import Genericclass FakeProvider:def __init__(self, provider):self.provider = providerself.count = 1def __dir__(self):return dir(self.provider)def __repr__(self):return f"FakeProvider({repr(self.provider)})"def __getattr__(self, name):subprovider = getattr(self.provider, name)wrapper = lambda *args, count=1, **kwargs: self.call_faker(subprovider, *args, **kwargs)wraps(subprovider)(wrapper)return wrapperdef __call__(self, count=1):self.count = countreturn selfdef call_faker(self, subprovider, *args, **kwargs):if self.count == 1:return subprovider(*args, **kwargs)else:return [subprovider(*args, **kwargs) for _ in range(self.count)]self.count = 1class Fake(object):def __init__(self, locale=Locale.EN):self.configure(locale)def get_factory(self, locale=Locale.EN, _cache={}):if isinstance(locale, str):locale = getattr(Locale, locale.upper())if locale in _cache:return _cache[locale]return Generic(locale=locale)def configure(self, locale=Locale.EN):self.factory = self.get_factory(locale)@propertydef fr(self):return self.get_factory(locale="fr")@propertydef en(self):return self.get_factory(locale="en")def __getattr__(self, name):return FakeProvider(getattr(self.factory, name))def __dir__(self):return ["fr", "en", *dir(self.factory)]fake = Fake()

在python会话中,我可以执行:

>>> fake.food(10).fruit()
['Kahikatea', 'Canistel', 'Hackberry', 'Bilberry', 'Genip', 'Cocona', 'Limeberry', 'Blueberry', 'Bilimbi', 'Redcurrant']

是时候了

如果必须在代码中提供日期,有两种方法可以使其易于测试。
第一,通过参数传递日期。例如:

def create_article(text, time_provider=datetime.datetime.now):Article(text, created_at=date_provider())

第二:使用黑魔法,在测试期间修补时间。

认识一下 freezegun,可以让你暂停时间:

>>> import datetime
... from freezegun import freeze_time
...
... def calendar_with_cheesy_quote():
...     print(f"{datetime.date.today():%B %d, %Y}")
...     print("Each day provide it's own gift")
...
... with freeze_time("2012-01-14"):
...     calendar_with_cheesy_quote()
...
January 14, 2012
Each day provide it's own gift

它与 pytest 集成,因此您可以装饰测试并假装您是 Timelord:

@freeze_time("Jan 14th, 2020") # you can use a nice format here too
def test_sonic_screwdriver_in_overrated_show_there_I_said_it():...

它可以从某个点开始时间,然后继续流动:

@freeze_time("2012-01-14", tick=True)
def test_turn_it_on_turn_it_on_turn_it_on_again():# the clock starts again here, and the first value is 2012-01-14 # at 00:00:00 then whatever number of seconds goes by after that

可以设置每次请求时间时增加 15 秒:

@freeze_time("2012-01-14", auto_tick_seconds=15)
def test_wheeping_angels_when_you_blink():# the clock starts again here, and the first value is 2012-01-14 # at 00:00:00 then every call to datetimes add 15 seconds

或手动控制时间:

 with freeze_time("2012-01-14") as right_here_right_now:right_here_right_now.tick(3600) # add 1H next time we request timeright_here_right_now.move_to(other_datetime) # jump in time

I/O

你将不得不读取和写入一些东西,如文件套接字。这些都是非常不可靠的副作用,所以嘲笑可能是你的第一个赌注。但是有一些专门的工具可以让你的生活更轻松。

众所周知,stdlib 附带了 tempfile 模块,该模块可以生成自动清理的临时文件和目录:

>>> import tempfile
... from pathlib import Path
...
... with tempfile.TemporaryDirectory() as temp_dir:
...     temp_path = Path(temp_dir)
...
...     (temp_path / 'subdir1').mkdir()
...     (temp_path / 'subdir2').mkdir()
...
...     (temp_path / 'file1.txt').write_text('This is file 1')
...     (temp_path / 'file2.txt').write_text('This is file 2')
...
...     print(f'Now you see me: {temp_dir}')
...     print(f'Contents: {list(temp_path.iterdir())}')
...
... print(f"Now you don't: {Path(temp_dir).exists()}")
Now you see me: /tmp/tmp67e3hjr2
Contents: [PosixPath('/tmp/tmp67e3hjr2/file1.txt'), PosixPath('/tmp/tmp67e3hjr2/subdir2'), PosixPath('/tmp/tmp67e3hjr2/subdir1'), PosixPath('/tmp/tmp67e3hjr2/file2.txt')]
Now you don't: False

即使在测试之外也很有用,但如果由于某种原因您不想触摸硬盘驱动器,则有pyfakefs

from pyfakefs.fake_filesystem_unittest import Patcher
from pathlib import Path
import oswith Patcher() as patcher:fs = patcher.fstemp_path = Path(os.path.join(os.sep, 'tmp', 'tempdir'))fs.create_dir(temp_path)(temp_path / 'subdir1').mkdir()(temp_path / 'subdir2').mkdir()(temp_path / 'file1.txt').write_text('This is file 1')(temp_path / 'file2.txt').write_text('This is file 2')print(f'Now you see me: {temp_path}')print(f'Contents: {list(temp_path.iterdir())}')fs.remove_object(temp_path)print(f"Now you don't: {temp_path.exists()}"")

就像冷冻枪一样,这是一个很大的黑魔法,但很有用。它将修补所有文件系统调用,并在内存中创建一个虚构的 FS,因此您的文件操作永远不会离开 RAM。
请注意,使用真实文件进行测试将允许您处理边缘情况,例如在多个分区上具有符号链接和树,这有时会令人惊讶。为正确的工作提供正确的工具等等。

由于我们处于内存领域,因此您可以使用 sqlite处理数据库

import sqlite3
connection = sqlite3.connect(':memory:')
cursor = connection.cursor()cursor.execute('CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT)')
cursor.execute('INSERT INTO test (name) VALUES ("Alice")')
cursor.execute('INSERT INTO test (name) VALUES ("Bob")')
connection.commit()cursor.execute('SELECT * FROM test')
rows = cursor.fetchall()
print('SQLite in-memory database contents:')
for row in rows:print(row)

这将在不接触磁盘的情况下创建一个数据库,这将是临时的,而且速度非常快。

最后,网络呢?

好吧,网络的工具和应用一样多,你会看到fakker redis, HTTP API, 中间人拦截,甚至全面的网络控制

不过,您可能会感兴趣的一个是 VCR.py,这是一个 Python 库,可以记录您的 HTTP 请求,并可以将其响应重放给您。

编写一个执行请求的测试,用@pytest.mark.vcr 标记它:

import pytest
import requests@pytest.mark.vcr
def test_single():assert requests.get("http://httpbin.org/get").text == '{"get": true}'

然后,针对真实网络运行一次:

pytest --record-mode=once test_network.py

下次您正常运行测试(移除 --record-mode ), VCR 将为您重播网络响应,并且您不会接触网络。

快照

我已经将一半的测试写入委托给 ChatGPT,然后在其中触发一个断点,这样我就可以窃取调用结果并将它们转换为断言。这是一个很好的技巧,它在许多情况下都有效。

当然,有一种方法可以进一步自动化!
inline-snapshot, 允许你写占位符,表示你的测试结果应该出现在哪里:

from inline_snapshot import snapshotdef test_something():assert 1548 * 18489 == snapshot() # snapshot() is the placeholder

然后运行测试以记录结果:

pytest --inline-snapshot=create

你会得到用以下值填充的测试:

神奇,你会发现文件自动变成了下面这个:

from inline_snapshot import snapshotdef test_something():assert 1548 * 18489 == snapshot(28620972)

您现在可以检查这些值是否有意义(不要相信它们,您的代码可能有问题),如果它们有效,请将它们提交到 git。下次正常运行它们(移除–inline-snapshot )时,快照中的数据将被透明地使用并据以测试。

您可以使用 --inline-snapshot=update 来更新自动更改的快照, --inline-snapshot=fix 仅更改不再通过的测试,或 --inline-snapshot=review 手动查看更改并批准更改,甚至 --inline-snapshot=disable 返回到原始值,并加快速度或检查快照是否是问题的原因。


评论是交互式的,非常方便:在这里插入图片描述
你可能会问,那些 external() 是什么。如果您不希望在测试代码中使用快照,则可以使用它。数据可能非常大,或者是一些非文本格式,会弄乱您的文件。您可以将测试结果标记为outsource

from inline_snapshot import outsource, snapshotdef test_a_big_fat_data():assert [outsource("long text\n" * times) for times in [50, 100, 1000]] == snapshot()

然后,当你用 --inline-snapshot=create ,它会变成这样:

from inline_snapshot import outsource, snapshot, externaldef test_a_big_fat_data():assert [outsource("long text\n" * times) for times in [50, 100, 1000]] == snapshot([external("362ad8374ed6*.txt"),external("5755afea3f8d*.txt"),external("f5a956460453*.txt"),])

文件存储在默认的 pytest 配置目录中,可以使用 --inline-snapshot=trim 删除过时的文件。

我喜欢这个库,因为您可以将快照的值直接放入代码中。我认为对于许多测试来说,它比从文件加载它更有意义。
但它有一个很大的局限性:你只能测试可以使用 repr() 的输出重新创建的东西,所以主要是 Python 内置的,如字符串、整数、列表字典和一些对象,如 datetime。如果你需要更复杂的对象,你就不走运了。
在这种情况下,您可以使用更强大的 pytest-insta,它允许 pickle作为序列化格式,因此您可以拍摄几乎所有内容的快照。如果你做不到,你可以创建自己的格式化程序,并使用像 cloudpickle 这样的黑魔法真正将任何怪物变成平面字节。

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

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

相关文章

计算机组成原理 | 硬件电路整理

计算机组成原理 | 硬件电路整理 桶形移位器原理图 全加器逻辑框图 多位可控加减法电路逻辑框图 可级联的4位先行进位电路 4位快速加法器 16位组内并行、组间并行加法器 实现原码一位乘法的逻辑框图 补码一位乘法的逻辑框图 无符号数阵列乘法器 原码不恢复余数法硬件逻辑框图 基…

规模弹性: 管理谷歌的TPUv4机器学习超级计算机(二)

本文为翻译文章,原文为: Resiliency at Scale: Managing Google’sTPUv4 Machine Learning Supercomputer。 由于字数过长,文章分为两期发布,本片涵盖原文后半部分4~9节,前三章节请参考文章:规…

Springboot应用的信创适配-补充

Springboot应用的信创适配-CSDN博客 因为篇幅限制,这里补全Spring信创适配、数据库信创适配、Redis信创适配、消息队列信创适配等四个章节。 Springboot应用的信创适配 Springboot应用的信创适配,如上图所示需要适配的很多,从硬件、操作系统、…

基于AT89C52单片机的温度报警系统

点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/89456321?spm=1001.2014.3001.5503 仿真构造:AT89C52+DS18B20温度模块+三按键+蜂鸣器+四位数码管显示+电源模块。 压缩包构造:源码+仿真图+设计文档+原理图+开题文档+元件…

Java宝藏实验资源库(3)类

一、实验目的 理解面向对象程序的基本概念。掌握类的继承的实现机制。熟悉类中成员的访问控制方法。熟悉ArrayList类的使用。 二、实验内容、过程及结果 *9.5Programming Exerc ise the GregorianCal endar class) Java API has the GregorianCalendar class in the java. uti…

民生银行北京分行金融科技校招面试记录

本文介绍2024届春招中,中国民生银行下属北京分行的金融科技岗位1场面试的基本情况、提问问题等。 2024年04月投递了中国民生银行下属北京分行的金融科技岗位,暂时不清楚所在部门。目前完成了一面与终面,在这里记录一下面试的相关经历。 首先&…

LayoutSystem布局系统

简介: LayoutSystem,是UGUI中由CanvasUpdateSystem发起(m_LayoutRebuildQueue中大部分都是LayoutRebuilder)的关于布局排列的处理系统。 类图: 布局过程 核心代码讲解: LayoutRebuilder

前端编程语言——JS语言结构、函数、数组、字符串、日期、对象、定时器(2)

0、前言: 这篇文章记录的是我自己的学习笔记。在python中通过input来获取输入,在JS中用prompt(),来获取输入。写JS代码要记得每个代码结束要加上分号。 1、JS编程语言结构: 顺序结构:从上往下依次执行分支结构&#…

【数据结构】顺序表实操——通讯录项目

Hi~!这里是奋斗的小羊,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~ 💥💥个人主页:奋斗的小羊 💥💥所属专栏:C语言 🚀本系列文章为个人学习…

三电平光伏逆变器高效DPWM研究

1. 引言 本文从效率 提升角度出发 , 详细分析了逆变器不同调制策略下开关 器件及滤波器损耗分布情况 , 并在 50kW 组串式三电平光伏逆变器上对比分析采用 SVPWM 和 DPWM 两种 调制方法对逆变器效率和谐波的影响 , 最终验证了采用 DPWM 调制策略的优越性。 2 SVPWM 和 DPWM 对比…

OpenCV 特征点检测与匹配

一 OpenCV特征场景 ①图像搜索,如以图搜图; ②拼图游戏; ③图像拼接,将两长有关联得图拼接到一起; 1 拼图方法 寻找特征 特征是唯一的 可追踪的 能比较的 二 角点 在特征中最重要的是角点 灰度剃度的最大值对应的…

ctfshow web 其他 web432--web449

web432 过滤了os|open|system|read|eval ?codestr(.__class__.__bases__[0].__subclasses__[185].__init__.__globals__[__builtins__][__import__](os).__dict__[popen](curl http://ip:port?1cat /f*)) ?codestr(.__class__.__bases__[0].__subclasses__()[185].__init_…

OpenCV Mat实现图像四则运算及常用四则运算的API函数

装载有图像数据的OpenCV Mat对象&#xff0c;可以说是一个图像矩阵&#xff0c;可以进行加、减、乘、除运算。特别是加运算特别有用。 一 与常数的四则运算 与常数的加运算 示例&#xff1a; #include <iostream> #include <opencv2/opencv.hpp>using namespace …

10.华为路由器使用ospf动态路由连通两个部门网络

目的&#xff1a;实验ospf动态路由协议连通A与B部门 AR1配置 [Huawei]int g0/0/0 [Huawei-GigabitEthernet0/0/0]ip add 1.1.1.1 24 [Huawei]vlan batch 10 [Huawei]int Vlanif 10 [Huawei]int e0/0/0 [Huawei-Ethernet0/0/0]port link-type access [Huawei-Ethernet0/0/0]por…

SpringCloud中Eureka和Nacos的区别和各自的优点

Eureka注册中心 Eureka作为一个注册中心&#xff0c;服务提供者把服务注册到注册中心&#xff0c;服务消费者去注册中心拉取信息&#xff0c; 然后通过负载均衡得到对应的服务器去访问。 服务提供者每隔30s向注册中心发送请求&#xff0c;报告自己的状态&#xff0c;当超过一定…

对比学习

对比学习基本概念 对比学习通过对比数据对的“相似”或“不同”以获取数据的高阶信息。 由同一张原始图片扩增而来的两张新的图片&#xff0c;叫做Positive Pairs。将这两张图片送入深度学习模型中&#xff0c;我们希望深度学习模型学习到这两个图像是相似的。 由不同原始图…

Flutter-实现头像叠加动画效果

实现头像叠加动画效果 在这篇文章中&#xff0c;我们将介绍如何使用 Flutter 实现一个带有透明度渐变效果和过渡动画的头像叠加列表。通过这种效果&#xff0c;可以在图片切换时实现平滑的动画&#xff0c;使 UI 更加生动和吸引人。 需求 我们的目标是实现一个头像叠加列表&…

【完全复现】基于改进粒子群算法的微电网多目标优化调度(含matlab代码)

目录 主要内容 部分代码 结果一览 下载链接 主要内容 程序完全复现文献模型《基于改进粒子群算法的微电网多目标优化调度》&#xff0c;以微电网系统运行成本和环境保护成本为目标函数&#xff0c;建立了并网方式下的微网多目标优化调度模型&#xff0c;通过改进…

游戏大厂“脱钩”安卓商店: 独立渠道TapTap们能否渔利

一纸公告将游戏厂商与渠道的博弈再度摆上了台面。 近日&#xff0c;腾讯控股旗下手游《地下城与勇士&#xff1a;起源》&#xff08;下称“DNF手游”&#xff09;运营团队发布公告称&#xff0c;自6月20日起&#xff0c;DNF手游将不再上架部分安卓平台的头部应用商店。 下架的…

idea添加文档注释

一、easy javadoc插件 在settings的plugins中下载easy javadoc插件。 安装完成后重启idea&#xff0c;再次打开settings界面。会出现easyDoc相关配置。 二、设置模版以及使用 类描述模版参考设置&#xff1a; /** * 类描述 -> * * Author: ywz * Date: $Date$ */ 方法描述…