Pytest:一个卓有成效的测试工具
大家都知道,目前最流行的Python单元测试框架有三种,分别是unittest, nose和pytest。其中unittest是Python自带的测试框架,但问题是比较老了,赶不上时代发展了(哈哈哈);nose2定位是带插件的unittest,实则对unittest的扩展。长远来看,pytest属于潜力股。
通过官网介绍的特点和使用经验,可以将pytest优点总结如下:
1)支持用简单的assert语句实现丰富的断言,无需复杂的self.assert*函数
2)可以自动识别测试模块和测试函数
3)兼容unittest和nose测试集
4)支持参数化
5)支持测试用例的skip和xfail处理
6)可以很好的和jenkins集成
7)支持丰富的插件,例如报告插件pytest-html、allure-pytest、失败重试插件pytest-rerunfailures、
8)活跃的社区,遇到的问题可以高效解决。
简化样板代码
大多数功能测试遵循 Arrange-Act-Assert 模型:
设置测试前置条件
调用函数来执行测试
断言执行结果
测试框架通常会挂接到测试的断言中,以便它们可以在断言失败时提供信息。unittest,例如,提供了许多开箱即用的断言方法,但是不友好的地方是,unittest编写的用例即使是一小部分测试也需要相当数量的样板代码。
下面写一个unittest测试用例并断言在项目中正常工作。
# test_with_unittest.py
from unittest import TestCase
class TryTesting(TestCase):
def test_always_passes(self):
self.assertTrue(True)
def test_always_fails(self):
self.assertTrue(False)
然后,你可以使用命令行运行这些测试:
(venv) $ python -m unittest discover
F.
======================================================================
FAIL: test_always_fails (test_with_unittest.TryTesting)
----------------------------------------------------------------------
Traceback (most recent call last):
File "...\effective-python-testing-with-pytest\test_with_unittest.py",
line 10, in test_always_fails
self.assertTrue(False)
AssertionError: False is not true
----------------------------------------------------------------------
Ran 2 tests in 0.006s
FAILED (failures=1)
一个测试通过,一个测试失败。OK,下面我们总结一下一个完整的测试需要写多少代码:
导入类unittest引入TestCase
创建TryTesting,一个子类TestCase
TryTesting为每个测试写一个方法
使用self.assert*方法进行断言
这是要编写的大量代码的,所以在开发测试用例时会一遍又一遍地编写相同的样板代码。而pytest则不同,它允许你直接使用普通函数和python assert关键字来简化样板代码达到相同的目的:
# test_with_pytest.py
def test_always_passes():
assert True
def test_always_fails():
assert False
就是如此简单。你需要做的就是写一个带有test_前缀的函数,使用assert关键字断言期望是True/False,然后执行测试即可。
Pytest不仅消除了很多样板代码,而且还提供了更加详细和易于阅读的输出。
更好的测试输出
在项目根目录文件夹下使用pytest命令运行所有测试用例:
(venv) $ pytest
============================= test session starts =============================
platform win32 -- Python 3.10.5, pytest-7.1.2, pluggy-1.0.0
rootdir: ...\effective-python-testing-with-pytest
collected 4 items
test_with_pytest.py .F [ 50%]
test_with_unittest.py F. [100%]
================================== FAILURES ===================================
______________________________ test_always_fails ______________________________
def test_always_fails():
> assert False
E assert False
test_with_pytest.py:7: AssertionError
________________________ TryTesting.test_always_fails _________________________
self = <test_with_unittest.TryTesting testMethod=test_always_fails>
def test_always_fails(self):
> self.assertTrue(False)
E AssertionError: False is not true
test_with_unittest.py:10: AssertionError
=========================== short test summary info ===========================
FAILED test_with_pytest.py::test_always_fails - assert False
FAILED test_with_unittest.py::TryTesting::test_always_fails - AssertionError:...
========================= 2 failed, 2 passed in 0.20s =========================
不同于unittest,pytest的测试结果展示的更详细:
系统状态,包括 Python的版本,pytest以及你安装的任何插件
测试目录
runner发现的测试数量
这些内容显示在输出的第一部分:
============================= test session starts =============================
platform win32 -- Python 3.10.5, pytest-7.1.2, pluggy-1.0.0
rootdir: ...\effective-python-testing-with-pytest
collected 4 items
输出使用以下的语法指示每个测试的状态:
点 (.)表示测试通过。
AnF表示测试失败。
AnE表示测试引发了意外异常。
特殊字符显示在用例名称后,右侧显示测试套件的整体进度:
test_with_pytest.py .F [ 50%]
test_with_unittest.py F. [100%]
对于失败的测试,报告会详细说明失败情况。
================================== FAILURES ===================================
______________________________ test_always_fails ______________________________
def test_always_fails():
> assert False
E assert False
test_with_pytest.py:7: AssertionError
________________________ TryTesting.test_always_fails _________________________
self = <test_with_unittest.TryTesting testMethod=test_always_fails>
def test_always_fails(self):
> self.assertTrue(False)
E AssertionError: False is not true
test_with_unittest.py:10: AssertionError
下面这个额外的输出在调试时非常有用。最后报告给出了测试用例执行的整体状态报告:
=========================== short test summary info ===========================
FAILED test_with_pytest.py::test_always_fails - assert False
FAILED test_with_unittest.py::TryTesting::test_always_fails - AssertionError:...
========================= 2 failed, 2 passed in 0.20s =========================
与 unittest 相比,pytest输出的信息量和可读性要高得多。
强大的assert
assert关键字很强大,支持丰富多样的断言形式。以下是一些断言示例,你可以了解支持的断言类型:
# test_assert_examples.py
def test_uppercase():
assert "loud noises".upper() == "LOUD NOISES"
def test_reversed():
assert list(reversed([1, 2, 3, 4])) == [4, 3, 2, 1]
def test_some_primes():
assert 37 in {
num
for num in range(2, 50)
if not any(num % div == 0 for div in range(2, num))
}
更容易管理前置参数和依赖
众所周知,测试用例通常需要依赖准备数据或者其他服务作为前置条件。
使用unittest,你可以将这些依赖项提取到方法中.setUp(),.tearDown()以便类中的每个测试都可以使用它们。使用这些特殊方法很好,但是随着你的测试类变得越来越大,你可能会不经意地使测试的依赖完全隐式。换句话说,通过孤立地查看众多测试中的一个,你可能不会立即看出它依赖于其他东西。
随着时间的推移,隐式依赖关系会导致代码变得复杂,你必须展开这些代码才能理解测试用例。事实上,测试应该有助于使你的代码更易于理解。如果测试本身很难理解,那么就有问题了!
pytest采取不同的方法。由于fixture的可用性,它会引导你进行显式的依赖声明,这些声明可以重用。fixture 是可以为测试用例创建数据、测试mock或初始化系统状态的函数。任何想要使用fixture的测试都必须显式地使用这个fixture函数作为测试函数的参数,所以依赖关系总是在前面声明:
# fixture_demo.py
import pytest
@pytest.fixture
def example_fixture():
return 1
def test_with_fixture(example_fixture):
assert example_fixture == 1
查看测试函数,你可以立即看出它依赖于一个fixture,而无需检查整个文件的fixture定义。
易于过滤测试
随着测试套件的增多,你可能会有只想对某个功能运行一些测试并保存整个套件以备后用的需求。pytest提供了一些方法来实现这一点:
基于名称的过滤:你可以限制pytest只运行那些完全限定名称与特定表达式匹配的测试。你可以使用-k参数执行此操作。
目录范围:默认情况下,pytest将仅运行当前目录中/下的测试用例。
测试分类:pytest可以包含或排除你定义的特定类别的测试,可以使用-m参数执行此操作。
测试分类是一个非常强大的工具。pytest使你能够为你喜欢的任何测试创建标签或自定义标签。一个测试可能有多个标签,你可以使用它们来精细化控制要运行的测试。
丰富的插件
pytest生态是开源的,pytest用户开发了一个丰富的有用插件生态系统。
fixture
Pytest fixture是一种为测试提供数据、测试mock的方法。每个依赖于fixture的测试都必须显式地接受fixture作为参数。
何时创建fixture
假设你正在编写一个函数format_data_for_display()来处理 API 接口返回的数据。输入数据是一个人员列表,每个人都有给定的姓名、姓氏和职位。该函数应输出一个字符串列表,其中包括每个人的全名、冒号和title:
# format_data.py
def format_data_for_display(people):
... # Implement this!
践行TDD模式,你需要为其编写测试用例。
# test_format_data.py
def test_format_data_for_display():
people = [
{
"given_name": "Alfonsa",
"family_name": "Ruiz",
"title": "Senior Software Engineer",
},
{
"given_name": "Sayid",
"family_name": "Khan",
"title": "Project Manager",
},
]
assert format_data_for_display(people) == [
"Alfonsa Ruiz: Senior Software Engineer",
"Sayid Khan: Project Manager",
]
在开发测试用例时,你可能需要开发另一个函数来将数据转换为逗号分隔值以便在Excel中使用:
# format_data.py
def format_data_for_display(people):
... # Implement this!
def format_data_for_excel(people):
... # Implement this!
你的TODO清单变长了!TDD 的优势之一是它可以帮助你规划未来的工作。format_data_for_excel()函数的测试看起来与format_data_for_display()函数非常相似:
# test_format_data.py
def test_format_data_for_display():
# ...
def test_format_data_for_excel():
people = [
{
"given_name": "Alfonsa",
"family_name": "Ruiz",
"title": "Senior Software Engineer",
},
{
"given_name": "Sayid",
"family_name": "Khan",
"title": "Project Manager",
},
]
assert format_data_for_excel(people) == """given,family,title
Alfonsa,Ruiz,Senior Software Engineer
Sayid,Khan,Project Manager
"""
值得注意的是,这两个测试都必须重复people变量的定义,而这需要相当多的代码。
如果你正在编写多个测试,这些测试都使用相同的底层测试数据,那么使用fixture你可以将重复的数据拉入一个装饰到函数中,使用@pytest.fixture表示该函数是一个pytest fixture:
# test_format_data.py
import pytest
@pytest.fixture
def example_people_data():
return [
{
"given_name": "Alfonsa",
"family_name": "Ruiz",
"title": "Senior Software Engineer",
},
{
"given_name": "Sayid",
"family_name": "Khan",
"title": "Project Manager",
},
]
# ...
你可以通过将函数引用作为参数添加到测试中来使用fixture,这样可以使用 fixture函数的返回值作为 fixture 函数的名称:
# test_format_data.py
# ...
def test_format_data_for_display(example_people_data):
assert format_data_for_display(example_people_data) == [
"Alfonsa Ruiz: Senior Software Engineer",
"Sayid Khan: Project Manager",
]
def test_format_data_for_excel(example_people_data):
assert format_data_for_excel(example_people_data) == """given,family,title
Alfonsa,Ruiz,Senior Software Engineer
Sayid,Khan,
"""
每个测试的代码量明显更短,但仍然有一条清晰的路径返回它所依赖的数据。
什么时候避免使用fixture
fixture非常适合提取你在多个测试中使用的数据或对象。但是,对于需要数据有变化的测试,fixture并不总是那么好。在你的测试套件中乱用fixture,可能会导致情况更糟。
与大多数抽象一样,需要一些实践和思考才能找到合适的fixture使用场景。
尽管如此,fixture 很可能是你的测试套件不可或缺的一部分。随着项目范围的扩大,测试规模的挑战开始出现。任何类型的工具面临的挑战之一是它如何应对大规模使用,pytest具有一系列有用的功能,可以帮助你管理用例增长带来的复杂性。
如何规模化使用fixture
当你从测试中提取更多的fixture时,你可能会发现一些fixture可以从进一步的抽象中受益。在 中pytest,fixture是模块化的。模块化意味着 fixture 可以导入,可以导入其他模块,它们可以依赖和导入其他 fixture。所有这些都允许你为你的用例编写合适的fixture抽象。
例如,你可能会发现两个单独文件或模块中的fixture共享一个共同的依赖项。在这种情况下,你可以将fixture从测试模块移动到更通用的fixture相关模块中,然后就可以将它们导入任何需要它们的测试模块中。
如果你想让一个fixture在你的整个项目中可用而不必导入它,可以使用特殊配置模块conftest.py文件。pytest在每个目录中查找一个conftest.py模块。如果你将通用fixture添加到conftest.py模块中,那么你将能够在整个模块的父目录和任何子目录中使用该fixture,而无需导入它。conftest.py是放置高频率使用fixture的好地方。
conftest.py另一个有用的地方是它可以保护对资源的访问。想象一下,你已经为处理API 调用的代码编写了一个测试套件,你希望确保测试套件不会进行任何真正的网络调用,即使有人不小心编写了这样做的测试。
pytest提供一个monkeypatch fixture来替换值和行为,你可以使用它来产生很好的效果:
# conftest.py
import pytest
import requests
@pytest.fixture(autouse=True)
def disable_network_calls(monkeypatch):
def stunted_get():
raise RuntimeError("Network access not allowed during testing!")
monkeypatch.setattr(requests, "get", lambda *args, **kwargs: stunted_get())
通过放置disable_network_calls()和conftest.py添加autouse=True的选项,你可以确保在整个套件的每个测试中都将禁用网络调用。任何执行代码调用的测试requests.get()都会引发一个RuntimeError指示将发生意外网络调用的错误。
marks:分类测试
在任何大型测试套件中,当你尝试快速迭代新功能时,最好避免运行所有测试,做好精细化测试。除了pytest在当前工作目录中运行所有测试的过滤功能之外,你还可以利用mark。
pytest使你能够为测试定义类别,并提供在运行套件时包含或排除类别的选项。你可以使用任意数量的类别标记测试。
标记测试对于按子系统或依赖项对测试进行分类很有用。例如,如果你的某些测试需要访问数据库,那么你可以@pytest.mark.database_access为它们创建一个标记。
当需要运行测试时,你仍然可以使用命令默认运行它们pytest。如果你只想运行那些需要访问数据库的测试,那么你可以使用pytest -m database_access. 要运行除需要访问数据库的测试之外的所有测试,你可以使用pytest -m "not database_access". 你甚至可以使用autousefixture来限制对那些标有 的测试的数据库访问database_access。
pytest-django插件提供了一个django_db标记。没有此标记的任何尝试访问数据库的测试都将失败。尝试访问数据库的第一个测试将触发 Django 测试数据库的创建。
pytest提供开箱即用的一些标记:
skip无条件跳过测试。
skipif如果传递给它的表达式的计算结果为True,则跳过测试。
xfail表示测试会失败,因此如果测试确实失败,整个套件仍会导致通过状态。
parametrize使用不同的值作为参数创建测试的多个变体。
Parametrization:组合测试
上文提到了如何使用fixture提取公共依赖项来减少代码重复。当你进行多个输入和预期输出略有不同的测试时,fixture就没有那么有用了。在这些情况下,你可以使用参数化为单个测试定义指定参数。
假设你编写了一个函数来判断一个字符串是否为回文。一组初始测试代码如下所示:
def test_is_palindrome_empty_string():
assert is_palindrome("")
def test_is_palindrome_single_character():
assert is_palindrome("a")
def test_is_palindrome_mixed_casing():
assert is_palindrome("Bob")
def test_is_palindrome_with_spaces():
assert is_palindrome("Never odd or even")
def test_is_palindrome_with_punctuation():
assert is_palindrome("Do geese see God?")
def test_is_palindrome_not_palindrome():
assert not is_palindrome("abc")
def test_is_palindrome_not_quite():
assert not is_palindrome("abab")
除了最后两个之外,所有这些测试都具有相同的样板:
def test_is_palindrome_<in some situation>():
assert is_palindrome("<some string>")
乍看很像样板文件。我们可以使用@pytest.mark.parametrize()减少测试代码:
@pytest.mark.parametrize("palindrome", [
"",
"a",
"Bob",
"Never odd or even",
"Do geese see God?",
])
def test_is_palindrome(palindrome):
assert is_palindrome(palindrome)
@pytest.mark.parametrize("non_palindrome", [
"abc",
"abab",
])
def test_is_palindrome_not_palindrome(non_palindrome):
assert not is_palindrome(non_palindrome)
第一个参数parametrize()是以逗号分隔的参数名称字符串。第二个参数是表示参数值的元组或单个值的列表。你可以将参数化进一步处理,将所有测试合并为一个:
@pytest.mark.parametrize("maybe_palindrome, expected_result", [
("", True),
("a", True),
("Bob", True),
("Never odd or even", True),
("Do geese see God?", True),
("abc", False),
("abab", False),
])
def test_is_palindrome(maybe_palindrome, expected_result):
assert is_palindrome(maybe_palindrome) == expected_result
尽管这缩短了你的代码,但重要的是要注意,在这种情况下,你实际上丢失了原始函数的一些更具描述性的特性。确保你没有将测试套件参数化到难以理解的地步之前,可以使用参数化将测试数据与测试行为分开,以便清楚测试用例在测试什么,同时也使不同的测试用例更易于阅读和维护。
durations
命令行使用--durations,pytest在测试结果中会包含持续时间报告。--durations需要一个整数值n,并将报告最慢的n测试:
(venv) $ pytest --durations=5
...
============================= slowest 5 durations =============================
3.03s call test_code.py::test_request_read_timeout
1.07s call test_code.py::test_request_connection_timeout
0.57s call test_code.py::test_database_read
(2 durations < 0.005s hidden. Use -vv to show these durations.)
=========================== short test summary info ===========================
...
显示在持续时间报告中的每个测试占用的总测试时间高于平均水平。
注:某些测试也可能有不可见的设置开销。例如django_db将触发 Django 测试数据库的创建。durations报告反映了在触发数据库创建的测试中设置数据库所花费的时间。
相关文章:
Pytest:一个卓有成效的测试工具
大家都知道,目前最流行的Python单元测试框架有三种,分别是unittest, nose和pytest。其中unittest是Python自带的测试框架,但问题是比较老了,赶不上时代发展了(哈哈哈);nose2定位是带插件的unitt…...

Compose 动画 (三) : AnimatedVisibility 从入门到深入
1. AnimatedVisibility 是什么 AnimatedVisibility可以实现Compose组件的显示和隐藏,并且可以指定显示/隐藏时候的动画效果。(EnterTransition/ExitTransition) 和 animateXxxAsState、animateContentSize、Crossfade、AnimatedContent 这几个API一起,都…...

网络基础(二)
目录 应用层 再谈 "协议" 协议是一种 "约定". socket api的接口, 在读写数据时, 都是按 "字符串" 的方式来发送接收的. 如果我们要传输一些"结构化的数据" 怎么办呢? 为什么要转换呢? 如果我们将struct message里面…...

Java线程知识点总结
文章目录Java 线程基础线程简介什么是进程什么是线程进程和线程的区别创建线程ThreadRunnableCallable、Future、FutureTaskCallableFutureFutureTaskCallable Future FutureTask 示例线程基本用法线程休眠线程礼让终止线程守护线程线程通信wait/notify/notifyAlljoin管道线程…...
数据结构——第三章 栈与队列(4)
队列的应用1.基于队列的医院挂号模拟系统2.队列的运用1.基于队列的医院挂号模拟系统 代码实现分享 2.队列的运用 问题描述:某运动会设立N个比赛项目,每个运动成员可以参加1~3个项目。试问如何安排比赛日程,既可以使同一运动员参加的项目不…...
华为机试HJ73-计算日期到天数转换
HJ73 计算日期到天数转换 题目描述: 描述 根据输入的日期,计算是这一年的第几天。 保证年份为4位数且日期合法。 进阶:时间复杂度:O(n) ,空间复杂度:O(1) 输入描述: 输入一行,每行…...
【阅读笔记】你不知道的JavaScript--this与对象2
目录this默认绑定隐式绑定隐式丢失显示绑定API 调用上下文new 绑定this 绑定优先级其余绑定例外对象字面量与对象属性描述符迭代器遍历this 默认绑定 默认绑定适配 独立函数调用 默认绑定 this 指向全局对象; 故直接调用函数,该函数内部的 this 即指向全…...

单板TVS接地不当造成辐射骚扰超标问题分析-EMC
【摘要】 某产品EMC辐射骚扰测试超标,通过近远场扫描配合定位分析,逐步找出骚扰源、传播路径,最终通过修改 PCB 走线切断传播路径解决此问题。 1 故障现象 某产品在进行 EMC 研发摸底测试时发现,整机辐射骚扰垂直方向测试超标&a…...

用Python Flask为女朋友做一个简单的网站(附可运行的源码)
🌟所属专栏:献给榕榕🐔作者简介:rchjr——五带信管菜只因一枚😮前言:该专栏系为女友准备的,里面会不定时发一些讨好她的技术作品,感兴趣的小伙伴可以关注一下~👉文章简介…...

vue3+rust个人博客建站日记5-所有界面
没有数据的前端,是没有灵魂的。明明标题是vue3 rust ,但日记撰写至今,似乎只有第一篇提及了Rust,这可不行。是时候一股作气,完成大部分页面绘制工作了! 最后再说一次,时间要加速了。 ——普奇神…...
青少年软件编程C++一级真题(202212)
1、输入一个整数x,输出这个整数加1后的值,即x1的值。 时间限制:1000 内存限制:65536 输入 一个整数x(0 ≤ x ≤ 1000)。 输出 按题目要求输出一个整数。 样例输入 9样例输出 10 #include<iost…...

【Spring】AOP底层原理(动态代理)-》 AOP概念及术语 -》 AOP实现
个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ AOP - 面向切面编程一、简述AOP二、AOP底层原理…...

Java8 新特性 之 lambda 表达 和 函数式接口
—— lambda 表达式 概念 lambda 表达式是一个匿名函数,可以把 lambda 表达式理解为是一段可以传递的代码。更简洁、更灵活,使 Java 的语言表达能力得到了提升lambda 表达式是作为接口的实现类的对象(万事万物皆对象) 使用语法…...
Netty服务端和客户端开发实例
一、Netty服务端开发在开始使用 Netty 开发 TimeServer 之前,先回顾一下使用 NIO 进行服务端开发的步骤。(1)创建ServerSocketChannel,配置它为非阻塞模式;(2)绑定监听,配置TCP 参数,例如 backlog 大小;(3)创建一个独立的I/O线程&…...

linux基本指令和权限
目录 一.shell命令以及运行原理 二.Linux常用指令 1. ls 指令 2. pwd命令 3.cd指令 4. touch指令 5.mkdir指令(重要) 6.rmdir指令 && rm 指令(重要) 7.man指令(重要) 8.cp指令(重要&…...

滚蛋吧,正则表达式!
大家好,我是良许。 不知道大家有没有被正则表达式支配过的恐惧?看着一行火星文一样的表达式,虽然每一个字符都认识,但放在一起直接就让人蒙圈了~ 你是不是也有这样的操作,比如你需要使用「电子邮箱正则表达式」&…...

序列号和反序列化--java--Serializable接口--json序列化普通使用
序列化和反序列化序列化和反序列化作用为什么需要用途Serializable使用serialVersionUID不设置的后果什么时候修改Externalizable序列化的顺序json序列化序列化和反序列化 序列化:把对象转换为字节序列的过程称为对象的序列化。 反序列化:把字节序列恢复为对象的过…...
Java异步任务编排
多线程创建的五种方式: 继承Thread类实现runnable接口。实现Callable接口 FutureTask(可以拿到返回结果,阻塞式等待。)线程池创建。 ExcutorService service Excutors.newFixedThreadPool(10); service.excute(new Runnable01());另外一种创建线程池…...

Hive与HBase的区别及应用场景
当数据量达到一定量级的时候,存储和统计计算查询都会遇到问题,今天了解一下Hive和Hbase的区别和应用场景。 一、定义 Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的sql查询功能&am…...

C++之单例模式
目录 1. 请设计一个类,只能在堆上创建对象 2. 请设计一个类,只能在栈上创建对象 3.请设计一个类,不能被拷贝 C98 C11 4. 请设计一个类,不能被继承 C98 C11 5. 请设计一个类,只能创建一个对象(单例模式) 设计…...

SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...

前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...