使用 Python 进行测试(5)测试的类型

news2024/11/25 2:24:31

总结

和我一起唱!
冒烟测试,让你快速失败;
回归测试,不打破过去;
健全性检查,保留所拥有;
集成测试,处理副作用;
端到端,永无尽头!
回测,所有的东西!
property tests have pros and cons, But they’ll guarantee your slot at PyCon. (属性测试有利有弊,但会保证你在PyCon的位置)

在这里插入图片描述

你知道的,命名是个麻烦事

我们今天会介绍一些行话(黑话),目的是让你了解测试的类别。

我们不会涵盖的内容

测试是一个广阔的领域。
检查类型提示是一种测试,linting 也是如此。将软件交到用户手中,看看他们如何使用它也是测试。有时你放一个摄像头,称之为人体工程学/可用性测试,有时你把它发布给一组选定的用户,并称之为alpha/beta测试,有时你把它随机施加到你的生产区域的一个子集,让每个人都感到困惑。这就是 A/B 测试。

一些公司有专门的部门来手动验证软件,他们可能称之为质量测试或验收测试。我有一些朋友根本没有自动化测试,但在每次发布之前,他们都会点击他们应用程序上的每个按钮。是的,这也是测试。

然后你有安全测试,以及各种模糊测试、红队和对抗性压力。再次测试。

还没完。将系统置于预期的压力下,这就是负载测试。把它放在极端的压力下,这就是压力测试。从长远来看,检查它在这些压力下的表现,这就是浸泡测试。看看当这个压力突然变化时它的表现,这就是尖峰测试。所有这些都被归入性能测试的保护伞下。

拔掉服务器是一种测试形式,听说过混沌猴子吗?

甚至审计也是一种测试形式。

由于我不是要写 900 页的三部曲,所以我将坚持单元测试集成测试端到端测试属性测试。这已经很多了,我们可能需要为每个人写一篇文章。此外,大多数人永远不会在进行所有这些类型测试的环境中工作。成本是巨大的,只有非常大的公司才能负担得起整个套餐。

单元测试(Unit tests)

当人们说测试时,通常说的就是这个。
如果你去维基百科,会看到:

单元测试,又名组件或模块测试,是一种软件测试形式,通过它测试隔离的源代码以验证预期行为。
单元测试描述了在单元级别运行的测试,以对比集成或系统级别的测试。

so,你隔离了一部分代码,进行测试,这部分代码成为单元(unit)。
什么部分?怎么隔离?怎么测试?维基百科进一步告诉我们:

单元通常意味着相对较少的代码量;可以与代码库的其余部分隔离的代码,这些代码库可能是一个庞大而复杂的系统。在过程编程中,单元通常是一个函数或模块。在面向对象编程中,单元通常是一个方法、对象或类。

所以基本上,你可以测试一个函数、一个方法、一个对象、一个类或一个模块。就像你可以驾驶三轮车、自行车、汽车、卡车或星际飞船一样。与银河系的其他其他驱动器隔离开来。

冒烟测试(Smoke testing)

冒烟测试是非常基本的初步测试,用于检查软件的基本功能是否正常。这基本上是为了节省你的时间:如果失败了,那么研究细节就没有意义了。

这是我经常写的第一个单元测试:

def test_import():
    from the_module import main_entry_point

为什么?因为 Python 被导入陷阱所困扰: sys.path 、循环依赖关系、阴影,应有尽有。导入可能会在测试之外失败,但这样我就不会有测试报告,我的测试会崩溃。如果我的项目根本没有加载,这个报告干净,没有歧义。这不仅适用于我,也适用于我的后辈搞砸了,不得不在聊天中报告一些事情。我可以告诉他们先运行这个测试。

冒烟测试有多种形式,就像我说的,它是一个去频谱。它不仅适用于单元测试,还可以进行端到端的冒烟测试,例如运行 CLI --version 并查看它是否返回错误代码。

使用冒烟测试有两个原因:

  • 作为测试的起点,它容易读写,并让人们参与进来。
  • 节省时间,如果冒烟出错了,就不用浪费时间调试更小的东西了。

回归测试

回归测试的主要好处是:保证不会破坏已有的好代码。

例如:

def test_add_strings(setup_and_tear_down):
    result = add("1", "2")
    assert result == "12"

这是一个回归测试,如果正确修改了代码,该测试应该同意通过。

健全性测试(Sanity tests)

回归测试的另一面是健全性检查:你确保特定的东西按预期工作。它节省了开发时间,而不是一次又一次地手动运行它,您可以将其委托给测试机器。它让您高枕无忧。它迫使你使用代码的 API,从而了解你的设计带来的权衡。当然,它会对规范的合规性进行编码,或者表明错误修复确实可以修复错误。

通常,回归测试只是旧的健全性检查。

我交替使用它们,对我来说这是一回事,这更像是上下文和词汇的问题,而不是实际的划分。但是你知道极客,我们喜欢分类法。

啊,我在开玩笑,我两者都不用。当我谈论它们时,我只是说“单元测试”,或者只是“测试”。团队知道。

单元测试的范围

我将在另一篇文章中专门讨论单元测试的良好实践。现在,假设单元测试是“不太大”的测试。在这一点上,我站在维基百科的一边。此外,大多数人倾向于同意单元测试是那些几乎没有副作用的单元测试,尤其是 I/O,例如网络调用、文件系统访问等。
如果你将一些不可变的参数传递给单个函数并检查结果,你将很难找到有人会认为这不是一个单元测试。

集成测试(Integration tests)

集成测试是检查“比单元测试更多,但比端到端少,并可以接受副作用”的测试。这是确切的科学定义。不要检查。

他们的目标是查看几个组件是否协同工作。比如,模型是否从缓存中加载?API 是否检查权限?
所以这是一个集成测试:

def test_user_authentication():
    user = auth_service.authenticate("username", "password")
    assert user is not None

因为尽管只有几行,但它对系统进行了大量操作,并且实际上它调用了另一个系统:数据库。
您希望集成测试易于单独运行,因为:

  • 它们比单元测试慢
  • 可能有副作用
  • 可能有肮脏的mock
  • 更脆弱

然而,在现场,它们只是混在一大堆测试中,与单元测试混合在一起是很常见的。毕竟,它们还可以检查回归或健全性,而且它们看起来很像单元测试。如果可以,请将它们放在单独的目录中,使用装饰器标记它们,或使用命名约定,以便可以筛选它们。

不幸的是,这并不总是可能的。坦率地说,并不总是可取的。请记住,这完全与目标和约束有关。如果运行整个测试套件需要 4 分钟以上,但将整个测试套件分开会花费很多,您可能不在乎。
分离的主要好处是迫使开发人员考虑其组件的纯度。缺点是开发人员可能过于关注组件的纯度。

许多项目都会有一个巨大的测试目录,其中大部分是集成测试,很少有单元测试,将整个 blob 称为“测试”,而且它们做得很好。不要对此过于强调。它可能是一个非常耦合的设计的标志,同样,这可能是一件好事,也可能是一件坏事,这取决于你的环境。不过,这值得研究,因为它可能会破坏一个项目。

现在,在美妙的 IT 世界中,总有一个问题。集成也用于“持续集成(continuous integration, CI)”的上下文中,即每次推送新代码时,在所有支持的平台上打包、安装和运行软件以及所有测试的做法。想想 GitHub Actions、Gitlab CI、Azure Pipelines、Travis、Jenkins…我们不想让彼此之间的沟通变得太容易,不是吗?
对于一个小团队和项目来说,持续集成是矫枉过正的。在发布之前进行手动检查阶段就足够了。使用 nox + doit 等工具可以轻松完成,以后您可以随时从该工具迁移到 CI。事实上,我的大多数 CI 只是在幕后打电话,因为我讨厌充满激情的模板化 YAML,并且每周都有撒旦仪式专门诅咒想出它们的人。
当您成长时,CI 在避免人为错误、执行策略、管理复杂性等方面变得方便。一旦您进行了大量的兼容性测试以检查不同的 Python 版本、浏览器、设备和操作系统,这绝对是无价的。但是,您公司的 Web API 精确地运行在 CentOS 6 + Python 3.5.1 上,您与一个 3 人团队一起开发,都在推动主 Git 分支,绝对可以推迟采用。

端到端测试(End-to-end tests)

简称为e2e,它是一种测试形式,试图以用户的方式执行系统的大部分内容。
让我们以联系表单为例,以及如何对其进行端到端测试:

import pytest
from playwright.sync_api import sync_playwright
from contact.models import ContactMessage

@pytest.mark.django_db
def test_contact_form_submission(playwright_context):

    # playwright is a lib to manipulate a web browser from python
    with sync_playwright() as playwright:
        # Start a real web browser with JS support and actually
        # navigate to the site
        browser = playwright.chromium.launch()
        context = browser.new_context()
        page = context.new_page()
        # Assume the server has been started somewhere else
        page.goto("http://localhost:8000/contact")

        # Fill the contact form
        page.fill('#name', 'John Doe')
        page.fill('#email', 'johndoe@example.com')
        page.fill('#message', 'Hello, this is a test message.')
        page.click('button[type="submit"]')

        # Wait for the form to be submitted and confirmation message to appear
        page.wait_for_selector('.success-message')
        browser.close()

    # Check if the contact message exists in the database
    assert ContactMessage.objects.filter(
        name='John Doe',
        email='johndoe@example.com',
        message='Hello, this is a test message.'
    ).exists()

您会注意到:

  • 它使用真正的浏览器、HTML、CSS 和 JS 测试前端。
  • 它执行 DOM 并形成交互。
  • 它检查 HTTP 堆栈,因为它发出真正的 POST 请求。
  • 它运行您的后端代码、验证、身份验证等。
  • 它确保数据库确实是最新的。
  • 它甚至可以确保响应按预期返回。

它们是一个很棒的 canari,可以快速告诉您是否会影响大量用户的东西正在疯狂运行。他们会告诉你,如果你破坏了UI,让人们感到困惑。他们会告诉你,如果你的集成测试错过了房间里的大象。他们会告诉你,如果你一直有错误的期望,并让你立足于现实。
有一些严肃的批评者对端到端测试咆哮。他们说它们很脆,维护成本高。

我同意它们在编写、读取和调试方面很混乱,而且工具可能会更好。

但他们脆弱的名声也是许多团队有的可怕习惯的结果,那就是破坏用户空间。

“快速行动,打破常规”,“尽早发布,经常发布”,“功能标志”以及所有那些非常聪明和成功的人卖给你的东西。你知道他们也做什么吗?让用户感到困惑,破坏客户的生产力,将支持变成猫捉老鼠的游戏,总而言之,粉碎了您的可靠性光环。

现在,我了解到,在产品的早期阶段,e2e测试基本上是一次性的。你正在学习,你没有稳定性保证,等等。需要保持灵活、精益和快速。

通常,只有少数几个可以缓解这种情况。主要代码路径。改变 10 个测试并不是世界末日,它会很快发现很多问题。

但是一旦你的产品稳定了,我发现端到端的测试可以让你保持诚实:如果你破坏了其中的200个测试,并且它们突然要花很多钱来更新,那么你可能正在做一些对用户不利的事情。

它们也是非技术人员能够很好地理解并可以做出贡献的测试。他们讲述用户故事。

但是,是的,它们很难书写和阅读。副作用、时间、混合上下文和跨越边界使它们变得混乱。我们也只有马马虎虎的工具包,测试 GUI 或 TUI 充其量只是我。如果您必须测试 PDF 输出,愿上帝怜悯。

此外,它们又慢又重,你当然不想在 Git 预提交钩子上运行它们。

尽早做 e2e,但只是一点点。甚至可能只有一个。这样可以保持多汁的股息,并且较低的进入成本。即使对于 CLI,也可以查看此示例中的 ROI,该示例用于测试发送 SMS 警报的命令行工具:

import pytest
import subprocess
import time
from twilio.rest import Client

# Twilio is a service that let you send text messages programmatically
account_sid = os.environ['TWILIO_SID']
auth_token = os.environ['TWILIO_TOKEN']
to_number = os.environ['TEST_USER_PHONE_NUMBER']
from_number = os.environ['TEST_SERVICE_PHONE_NUMBER']

def test_send_sms():
    test_message = "This is a test message"
    # Run the CLI command in a different process
    subprocess.run(['python', 'send_sms.py', test_message, to_number], check=True)

    # Wait for the message to be sent and received
    time.sleep(10)

    twilio_client = Client(account_sid, auth_token)
    messages = twilio_client.messages.list(to=to_number, from_=from_number, limit=1)
    assert len(messages) > 0
    assert messages[0].body == test_message

我们行使一切,参数解析,网络调用,接收,消息完整性,我们的帐户订阅已支付(尽管它非常重要并且搞砸了世界各地的许多公司,但没有人测试过)…

当然,它有很多问题:

  • 网络或 Twilio 可能会瘫痪。
  • sleep时间可能会有一天关闭。
  • 我们不依赖向该号码发送消息的其他任何内容。
  • 如果你搞砸了,比如引入一个循环调用该测试的错误,它可能会花费你很多钱。

但是你不能躲在关注点的分离后面,如果链条的任何部分薄弱,你的产品坏了,你就会知道。

一旦产品成熟,就要加倍努力。将它们与您的单元和集成测试保持良好分离。它们不应该相互影响。您应该能够破坏私有 API,而不会完全影响 e2e。您应该能够更改您练习 UI 的方式,而无需使用较小的部分来实现它。

最后,我再说一遍,请记住,测试是一个频谱。您不必处于绝对的一端,端到端才有价值。使用 FastAPI 查看该示例:

from fastapi import FastAPI
from fastapi.testclient import TestClient
from our_project.site import fast_api_app

client = TestClient(fast_api_app)

def test_read_user_profile():
    response = client.get("/me")
    assert response.status_code == 200
    assert response.json() == {"username": "BiteCode", "id": "987890789790"}

它测试整个 API 端点,包括数据库调用,但不会旋转真实服务器,因为它使用创建 Python HTTP 请求对象而不是解析字节字符串的测试客户端。它也没有执行真正的客户端解析响应。

Is that e2e? Is that integration testing? Maybe it’s Maybelline.
谁在乎,它很有用。
把它放在其中一个文件夹中,同意你的团队始终如一地这样做,然后转到下一个可交付成果。

回测(Backtesting)

回溯测试是测试中被忽视的领域,你会发现它主要发生在机构中的大型、有风险的长跑运动员身上。

这是一个积累输入和输出的过程,你知道这些输入和输出应该对你的系统有效,然后定期向它提供整个数据集,以检查它是否仍然像这样运行。

它是回归和端到端测试的混合体,两者各有利弊。

它成本高昂、速度慢,并且会使您的功能集变得石化。

但是,您这样做的时间越长,您的系统就越可靠,尤其是在错误和边缘情况的长尾中。有些用户会喜欢你,因为你一直在他们身边,有些用户会讨厌你,因为你从未现代化。此外,您还必须大量处理架构版本控制。

简而言之,它非常适合银行支付系统,而对于热门的启动手机应用程序来说完全不够用。

它是什么样子的?

想象一下,一个交易者想要改变他的加密货币机器人行为,但希望看到在相同的市场下,与之前的策略相比,这将如何影响他的收益:

import pandas as pd

# Load historical data

# Kryll is a veteran token that powers an automated trading platform, 
# which, funnily, provide a UI to create strategies and backtest 
# them without code. But pandas is free :)

df = pd.read_csv('kryll_historical_data.csv', parse_dates=['Date'])
df.set_index('Date', inplace=True)

# Calculate moving averages.
short_window = 40
long_window = 100

df['SMA40'] = df['Close'].rolling(window=short_window, min_periods=1).mean()
df['SMA100'] = df['Close'].rolling(window=long_window, min_periods=1).mean()

# Define the trading signals
df['Signal'] = 0
df['Signal'][short_window:] = np.where(df['SMA40'][short_window:] > df['SMA100'][short_window:], 1, 0)
df['Position'] = df['Signal'].diff()

# Initialize backtesting variables
initial_capital = 100000.0
positions = pd.DataFrame(index=df.index).fillna(0.0)
portfolio = pd.DataFrame(index=df.index).fillna(0.0)

# Simulate trades. This is BS, but have you worked in finance?
positions['Kryll'] = df['Position'] * initial_capital / df['Close']
portfolio['Positions'] = (positions.multiply(df['Close'], axis=0)).sum(axis=1)
portfolio['Cash'] = initial_capital - (positions.diff().multiply(df['Close'], axis=0)).sum(axis=1).cumsum()
portfolio['Total'] = portfolio['Positions'] + portfolio['Cash']

# Calculate returns
portfolio['Returns'] = portfolio['Total'].pct_change()

# Display the portfolio and performance metrics
print(portfolio)

# Plot the results
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(12, 8))
ax.plot(df.index, portfolio['Total'], label='Portfolio Value')
ax.plot(df.index, df['Close'], label='Kryll Close Price', alpha=0.5)
ax.set(title='Backtest of SMA Crossover Strategy', xlabel='Date', ylabel='Value')
ax.legend()
plt.show()

我保留了量化代码的美妙风格,包括内联导入,这样你就可以体验到我们的经济所依赖的东西。我在开玩笑,加上我根本没有测试过这个脚本,它更接近伪代码。

回溯测试不一定是完全自动化的,也不一定是一对一的匹配才有用。有时你希望你的系统表现得和以前完全一样,但有时你只是希望趋势大致相似或更好,因为你知道不可能得到完全相同的结果。

这就是它在这里的内容:我们在脚本末尾显示结果的 matplotlib 曲线,因此我们可以直观地检查结果与之前的结果进行比较。

当然,并非所有的回测都是这样的。有些需要完美的对齐并且不涉及人类,但您的数据集越大,它发生的可能性就越小,甚至不可能发生。现实充满了复杂性。

属性测试(Property tests)

也被称为“我们在 PyCon 上看到过,还记得吗?”,因为每个听说过它的人都认为它很酷,但实际这样做的人数接近 Raspberry Pi 上的引脚数量。

这个想法是运行代码,但不是测试结果,而是检查无论输入是什么,通用属性是否仍然为 true。然后,一个工具(在Python中,通常是优秀的假设)将尝试将各种垃圾传递给它,直到它崩溃。
我发誓,这非常有用。

首先选择一个单元测试来练习程序的关键部分。属性测试既缓慢又昂贵,因此您通常从小处着手。您还希望避免副作用,因为代码将以不受控制的方式运行数百万次,因此很难管理因果关系链。这是与一般模糊测试的主要区别,一般模糊测试实际上旨在制造混乱,并且这可能是可取的,尤其是对于安全性而言。

让我们回到本系列文章的第 2 部分中的 add() 示例。我们有:

import random

import pytest
from the_code_to_test import add


@pytest.fixture()
def random_number():
    yolo = random.randint(0, 10)
    yield yolo
    print(f"\nWe tested with {yolo}")


@pytest.fixture()
def setup_and_tear_down():
    print("\nThis is run before each test")
    yield
    print("\nThis is run after each test")


def test_add_integers(setup_and_tear_down, random_number):
    result = add(1, 2)
    assert result == 3
    result = add(1, -2)
    assert result == -1

    assert add(0, random_number) > 0


def test_add_strings(setup_and_tear_down):
    result = add("1", "2")
    assert result == "12"


def test_add_floats():
    result = add(0.1, 0.2)
    assert result == pytest.approx(0.3)


def test_add_mixed_types():
    with pytest.raises(TypeError):
        add(1, "2")

我们怎么知道我们测试了所有边缘情况并找出了所有错误?这当然是不可能的,但我们有多大的信心去追逐所有最明显的目标?
现在你的直觉是,对于这样一个简单的函数,域是相当明显的,我们不可能错过什么。我的意思是,来吧,这是 add() !
但像往常一样,编程是在嘲笑我们的天真,而且有龙。
假设在这里可以提供帮助,所以让我们在拥有 pip installed hypothesis-pytest 条件后再创建一个测试:

import pytest
from the_code_to_test import add
from hypothesis import given, strategies as st

@given(st.one_of(st.integers(), st.floats()), st.one_of(st.text(), st.integers(), st.floats()))
def test_add_mixed_types_property(a, b):
    if isinstance(a, (int, float)) and isinstance(b, (int, float)):
        result = add(a, b)
        assert result == a + b
    else:
        with pytest.raises(TypeError):
            add(a, b)

我不会在这里详细介绍,会有一篇专门介绍属性测试的文章。但从本质上讲,我们告诉假设我们想检查属性,说明“使用 add() 时,要么我们传递相同的类型,结果为相同的类型,要么我们没有传递相同的类型,并且存在错误”。

理智行为:添加字符串,取回字符串。添加浮点数,取回浮点数。添加一个字符串和一个 int,这是一个错误。
从这个测试中,假设将生成大量输入数据的组合,运行代码并试图证明我们只不过是愚蠢的小猿猴,愚蠢地相信我们一直在控制之中。
可能出什么问题?
房间里所有因这个问题而遭受巨大痛苦的数据科学家,都已经以一种心爱的印度面包的形式尖叫着答案,但讨厌浮点值:

a = 0, b = nan

    @given(st.one_of(st.integers(), st.floats()), st.one_of(st.text(), st.integers(), st.floats()))
    def test_add_mixed_types_property(a, b):
        if isinstance(a, (int, float)) and isinstance(b, (int, float)):
            result = add(a, b)
>           assert result == a + b
E           assert nan == (0 + nan)
E           Falsifying example: test_add_mixed_types_property(
E               a=0,
E               b=nan,  # Saw 1 signaling NaN
E           )

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

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

相关文章

SwiftUI 6.0(Xcode 16)全新 @Entry 和 @Previewable 宏让开发妙趣横生

概览 如火如荼的 WWDC 2024 已进入第五天,苹果开发平台中众多海量新功能都争先恐后的喷薄欲出。 在这里就让我们从中挑两个轻松有趣的新功能展示给小伙伴们吧:它们分别是 全新的 Entry 和 Previewable 宏。 在本篇博文中,您将学到如下内容&a…

用React编写一个密码组件表单

theme: condensed-night-purple highlight: atelier-cave-light 背景介绍 我们在使用网站或者应用程序的登录界面或创建帐户界面时,往往避免不了需要用户输入密码这一步骤,而用户是否可以选择看见他们输入的密码是十分重要的一项功能。尤其是在当输入的…

Focusky是什么软件

Focusky是一款基于HTML5技术的多媒体演示软件,可以轻松地制作出生动有趣的PPT演示文稿、动画宣传片以及微课。与其他软件相比,Focusky拥有丰富的多媒体资源和动画效果,可以让演示内容更加生动。本文将为您详细介绍Focusky软件的功能&#xff…

awd工具安装

fscan(漏洞扫描) 下载 下载地址: Releases shadow1ng/fscan GitHub 把下载的文件放到指定文件目录里, 在文件的位置打开cmd 输入 fscan64.exe -h 192.168.1.1/24 ok了 接下来说说fscan的使用 使用 1.信息搜集: 存活探测(icmp) 端口扫描 2.爆破功能: 各类服务爆破(…

MongoDB~高可用集群介绍:复制集群(副本集)、分片集群

背景 MongoDB 的集群主要包括副本集(Replica Set)和分片集群(Sharded Cluster)两种类型。 副本集 组成:通常由一个主节点(Primary)和多个从节点(Secondary)构成。 功…

UniVue更新日志:使用ObservableList优化LoopList/LoopGrid组件的使用

github仓库 稳定版本仓库:https://github.com/Avalon712/UniVue 开发版本仓库:https://github.com/Avalon712/UniVue-Develop UniVue扩展框架-UniVue源生成器仓库:https://github.com/Avalon712/UniVue-SourceGenerator 更新说明 如果大家…

Django REST framework视图集与路由详解:深入理解ViewSet、ModelViewSet与路由映射器

系列文章目录 Django入门全攻略:从零搭建你的第一个Web项目Django ORM入门指南:从概念到实践,掌握模型创建、迁移与视图操作Django ORM实战:模型字段与元选项配置,以及链式过滤与QF查询详解Django ORM深度游&#xff…

【java】数学运算考试系统

目录 一、登录界面: 二、管理员界面: 三、学生考试界面: 面向小学低年级学生,随机生成两个整数的加减法算式要求学生解答。要求有用 户登录、注册等 GUI 界面,用户数据存入文件,体现面向对象编程思想。 …

windows11子系统Ubuntu 22.04.4子安装图形化界面

1、windows11家庭版本设置 打开虚拟机安装许可 2、Microsoft Store下载安装ubuntu 我使用的是22.04.4 LTS版本 3、 打开ubuntu 命令窗口 1、打开win11的命令行,在下拉三角下标,打开,可以看到有Ubuntu 的选项,点击即可进入linux命…

【Android面试八股文】你说一说什么是双亲委托机制?为什么需要双亲委托机制?

一、双亲委托机制 1.1 双亲委托机制概述 双亲委托机制是指当一个类加载器收到一个类加载请求时, 该类加载器首先会把请求委派给父类加载器。 如果父类加载器还存在父类加载器,则会一直向上委派,直至最终交由顶层的启动类加载器完成类加载, 每个类加载器都是如此,只有在所…

RIP解决不连续子网问题

#交换设备 RIP解决不连续子网问题 一、不连续子网的概念 相同主网下的子网,被另一个主网分割,例如下面实验拓扑在某公司的网络整改项目中,原先R1 和RS 属于同一主网络 10.0.0.0/8,现被 R2、R3、R4 分离,整网采用了 …

Docker 安装 MySQL5.7 和 MySQL8

文章目录 安装 MySQL5.7拉取镜像前期准备启动容器 安装MySQL8.0拉取镜像查看镜像前期准备启动容器 安装 MySQL5.7 拉取镜像 docker pull mysql:5.7拉下来镜像后 执行 docker images 此时我们已经有这个镜像了。 前期准备 在根目录下创建 app , 在 app 目录下创建…

牛客周赛 Round 47 解题报告 | 珂学家

前言 题解 这真的是牛客周赛? 哭了 欢迎关注 珂朵莉 牛客周赛专栏 珂朵莉 牛客小白月赛专栏 A. 小红的葫芦 签到题 但是写起来有点变扭,方法应该蛮多的 统计分组 有2组一组长度为2,一组长度为3 def check(arr):arr.sort()if arr[0] …

数据结构试题 20-21

真需要就死记吧 二叉树遍历-先序(非递归)【图解代码】_哔哩哔哩_bilibili 解释一下步骤: 一个循环为: 1.取节点 2.放右子树 3.放左子树 每次循环,都要从栈里取出一个节点 先放右子树,再放左子树 那这道题就是,先放1&am…

内网Docker镜像无法使用?Debian/Ubuntu离线安装Dokcer

离线安装Docker 卸载冲突的包 for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done先删除docker sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin d…

DSP28335:独立按键控制LED灯

做任何事情不可操之过急,虽然我们可能在之前的单片机学过相关的原理,但是一个新的单片机依然有他的学习的地方,之前我觉得很简单,就跳过这个学习,结果到后面就很浮躁,导致后面的内容与这一章相连接的时候&a…

调用第三方系统的签名设计与校验实例讲解与实践

在现代软件开发中,调用第三方系统API已经成为常见需求。为了保证数据传输的安全性和完整性,许多API采用了签名机制。本文将详细讲解如何设计与校验调用第三方系统的签名,以确保双方通信的安全和可靠。 #### 一、签名机制的意义 签名机制主要…

.gitignore文件忽略的内容不生效问题解决

文章目录 ①:现象②:原因③:解决 ①:现象 在已经提交过的git管理的项目中, 新增加一个.gitignore文件,文件内忽略内容不生效或者修改.gitignore文件之后,文件内新增的忽略内容不生效 ②&#…

Dell戴尔灵越Inspiron 16 Plus 7640/7630笔记本电脑原装Windows11下载,恢复出厂开箱状态预装OEM系统

灵越16P-7630系统包: 链接:https://pan.baidu.com/s/1Rve5_PF1VO8kAKnAQwP22g?pwdjyqq 提取码:jyqq 灵越16P-7640系统包: 链接:https://pan.baidu.com/s/1B8LeIEKM8IF1xbpMVjy3qg?pwdy9qj 提取码:y9qj 戴尔原装WIN11系…

1.华为路由器-三层交换机-二层交换机组网连接

AR1配置GE 0/0/0接口IP [Huawei]int g0/0/0 [Huawei-GigabitEthernet0/0/0] [Huawei-GigabitEthernet0/0/0]ip add 1.1.1.1 24 [Huawei]iP route-static 192.168.0.0 16 1.1.1.2三层交换机配置如下 创建vlan [Huawei]vlan batch 10 20配置接口ip [Huawei]int g0/0/1 [Huawei…