news 2026/9/2 20:29:15

Python类与模块:自动化测试与接口测试的工程化基石

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python类与模块:自动化测试与接口测试的工程化基石

第四课是这套软件测试入门到精通系列教程里最关键的一次转折:前几课还在讲变量、分支、循环这些"单打独斗"的语法,从这节课开始,我们进入 Python 工程化的核心——类与模块。

为什么这一课对所有想转自动化测试、接口测试的零基础同学特别重要?因为你只要打开任何一家公司的测试框架,第一眼看到的必然是class TestLoginfrom common.api_client import APIClient这类代码。看不懂类和模块,你就只能复制粘贴别人写好的用例模板,出了问题根本不知道去哪排查。

这节课我会拆成三块来讲:先讲类的定义、对象创建和self的本质,再讲模块的导入机制与if __name__ == '__main__'的底层逻辑,最后用一个登录接口测试的实战案例,把类和模块串成一套最小可用的自动化测试项目。学完之后,你至少能独立读懂 pytest 测试类、PO 模式页面对象类,并且能自己动手搭建一套测试项目的目录结构。

1. 本课学习地图:类与模块到底解决什么问题

很多零基础同学学 Python 时最迷惑的一点是:我明明用函数就能写测试脚本,为什么还要学类?函数把一段逻辑封装起来,类把"数据 + 操作数据的方法"封装起来,模块则把相关的类、函数、变量继续归档。

放在软件测试里,区别非常明显:

对比维度只用函数使用类 + 模块
测试数据组织靠全局变量或函数传参类的属性天然承载数据
公共操作复用复制粘贴函数调用继承基类复用全部能力
命名空间大量同名函数互相覆盖类名 + 方法名双重隔离
项目结构一个脚本堆到底按模块拆分,多人协作
排查问题靠人肉搜索按模块、类、方法逐层定位
pytest 组织fixture 到处散落测试类内聚、conftest 统一管理

本课核心目标可以浓缩成四句话:

  1. 能写出规范的测试类,交给 pytest 自动收集执行。
  2. 能设计一个 API 封装类,把接口请求和断言分开。
  3. 能理解 Python 模块导入机制,解决ModuleNotFoundError
  4. 能用包结构搭建一套可维护的测试工程,而不是把所有代码塞进一个.py文件。

下面进入正题。顺序是:先会写类,再会用类,最后把类装进模块。

2. 类和对象:把测试数据变成结构体

2.1 为什么测试数据需要一个"容器"

先看一个最常见的测试场景:登录接口需要用户名、密码、期望状态码、期望提示信息。如果只用变量,你会写出这种东西:

username = "admin" password = "123456" expected_code = 200 expected_msg = "登录成功"

这个写法的问题是:如果系统里有 10 个测试用户,你得写 40 个变量;如果要传给函数,得按顺序传参,稍不留神就把passwordusername传反。类在这里的作用,是把一组相关的数据打包成一个整体,不需要关心内部每个字段的顺序。

class LoginUser: def __init__(self, username, password, expected_code, expected_msg): self.username = username self.password = password self.expected_code = expected_code self.expected_msg = expected_msg user1 = LoginUser("admin", "123456", 200, "登录成功") user2 = LoginUser("tester", "abc123", 200, "登录成功") user3 = LoginUser("locker", "wrong_pwd", 401, "用户名或密码错误") print(user1.username) # admin print(user3.expected_msg) # 用户名或密码错误

这就是类的第一个价值:它是测试数据的结构体。你不再面向一堆散落的变量编程,而是面向一个个有名字的测试对象编程。

2.2 类的定义与__init__构造函数

所有 Python 类都通过class 类名:定义,类名习惯使用大驼峰命名。

__init__是构造函数,在创建对象时自动执行。它的作用是初始化对象的状态,也就是给对象填上"出生自带的数据"。

class TestCaseInfo: def __init__(self, case_id, title, module, preconditions): self.case_id = case_id self.title = title self.module = module self.preconditions = preconditions case = TestCaseInfo("TC001", "验证正确用户名密码可以登录", "登录模块", "系统已初始化")

注意__init__的第一个参数永远是selfself不是 Python 关键字,它只是一个约定俗成的名字,代表"当前正在创建的对象自己"。当你写case.title时,Python 会自动把case当作self传进去。

2.3 实例属性与类属性

继续用测试场景说明这两种属性的区别。

class TestConfig: # 类属性:所有对象共享 base_url = "https://api.example.com" timeout = 5 def __init__(self, env): # 实例属性:每个对象独立 self.env = env config_dev = TestConfig("dev") config_prod = TestConfig("prod") print(config_dev.base_url) # https://api.example.com print(config_prod.base_url) # https://api.example.com

类属性相当于所有对象共用的默认配置,实例属性相当于每个对象各自的环境变量。

2.4 常见的面试考察点

软件测试面试题里经常出现一个对比:clsself、实例方法、类方法、静态方法。这里先看代码:

class TestDemo: version = "1.0" def __init__(self, name): self.name = name def instance_method(self): # 实例方法:能访问实例属性,也能访问类属性 return f"实例方法:{self.name},版本 {self.version}" @classmethod def class_method(cls): # 类方法:只能访问类属性,不能访问实例属性 return f"类方法:版本 {cls.version}" @staticmethod def static_method(msg): # 静态方法:与类和实例都没有绑定关系 return f"静态方法:{msg}" obj = TestDemo("登录用例") print(obj.instance_method()) print(TestDemo.class_method()) print(TestDemo.static_method("不访问任何对象属性"))

在测试框架中最常用的是实例方法:因为实例方法可以同时拿到当前测试对象的数据(self.name)和公共配置(self.version)。类方法和静态方法一般用于工具类的封装,后面实战部分会遇到。

3. 面向对象三大特性在自动化测试中的应用

3.1 封装:把接口请求细节藏起来

接口测试最忌讳每个用例都从头写一遍requests.post()。利用类的封装特性,可以把 HTTP 请求统一封装到一个ApiClient类里,调用方只关心client.post()返回什么,不关心底层怎么发请求。

import requests class ApiClient: def __init__(self, base_url, token=None): self.base_url = base_url self.headers = {"Authorization": f"Bearer {token}" if token else ""} def post(self, path, data=None, json=None): url = self.base_url + path response = requests.post(url, data=data, json=json, headers=self.headers, timeout=10) return response def get(self, path, params=None): url = self.base_url + path response = requests.get(url, params=params, headers=self.headers, timeout=10) return response

这样一来,具体的测试用例完全不用关心requests库的细节,只管调用api.post("/login", json=payload)。排查问题时的范围也被压缩了:请求层出错看ApiClient,业务层出错看用例本身。

3.2 继承:让测试用例共享公共逻辑

当你有多个测试类都需要"登录后拿 token"这个前置操作时,不需要在每个类里重复写一遍,而是抽一个BaseTest基类:

class BaseTest: def setup(self): self.client = ApiClient("https://api.example.com") self.token = self.login_and_get_token() def login_and_get_token(self): response = self.client.post("/login", json={"username": "admin", "password": "123456"}) return response.json().get("token") class TestLogin(BaseTest): def test_login_success(self): assert self.token is not None class TestUserInfo(BaseTest): def test_get_user_info(self): response = self.client.get("/user/info") assert response.status_code == 200

TestLoginTestUserInfo都继承了BaseTest,各自不需要再写setup里的重复逻辑。这就是继承在测试项目里的最大价值:把公共前置步骤上浮到基类。

3.3 多态:不同测试数据源走同一个接口

如果你需要支持从 JSON 文件、Excel 表格、YAML 配置中读取测试数据,多态可以让调用方用完全一致的方式处理不同的数据源:

class DataReader: def read(self): raise NotImplementedError class JsonReader(DataReader): def __init__(self, file_path): self.file_path = file_path def read(self): import json with open(self.file_path, "r", encoding="utf-8") as f: return json.load(f) class ExcelReader(DataReader): def __init__(self, file_path): self.file_path = file_path def read(self): # 实际项目中用 openpyxl 或 pandas 实现 return [{"username": "admin", "password": "123456"}] def load_test_cases(reader: DataReader): return reader.read() json_cases = load_test_cases(JsonReader("data/test_data.json")) excel_cases = load_test_cases(ExcelReader("data/test_data.xlsx"))

调用方只依赖DataReader.read()这个统一入口,具体是 JSON 还是 Excel,由传入的对象决定。这段代码在面试中经常作为"请简述多态在测试框架中的应用"的答案模板。

4. 特殊方法:让断言和日志更顺手

Python 类里还有一批以双下划线开头和结尾的特殊方法,在测试场景中有三个非常实用。

4.1__str____repr__:让测试对象可以友好打印

如果你直接打印一个测试数据对象,看到的是<__main__.LoginUser object at 0x...>,完全不可读。实现__str__后,打印结果变得直观:

class LoginUser: def __init__(self, username, password, expected_code, expected_msg): self.username = username self.password = password self.expected_code = expected_code self.expected_msg = expected_msg def __str__(self): return f"LoginUser({self.username}, {self.expected_msg})" __repr__ = __str__ user = LoginUser("admin", "123456", 200, "登录成功") print(user) # LoginUser(admin, 登录成功)

在 pytest 的断言失败信息里,repr输出会直接出现在日志中,能帮助你更快定位是哪条测试数据出了问题。

4.2__eq__:自定义对象比较逻辑

断言assert resp1 == resp2时,如果两边都是自定义类对象,Python 默认比较的是内存地址,结果永远为 False。通过__eq__可以定义两个对象相等时应该比较哪些字段:

class ApiResponse: def __init__(self, status_code, body): self.status_code = status_code self.body = body def __eq__(self, other): if not isinstance(other, ApiResponse): return False return self.status_code == other.status_code and self.body == other.body resp1 = ApiResponse(200, {"message": "success"}) resp2 = ApiResponse(200, {"message": "success"}) print(resp1 == resp2) # True

4.3__call__:让测试对象可以像函数一样调用

如果在自动化测试中要描述一个"可重复执行的检查动作",可以让类的实例拥有函数一样的调用方式:

class StatusCodeChecker: def __init__(self, expected_code): self.expected_code = expected_code def __call__(self, response): assert response.status_code == self.expected_code, \ f"期望状态码 {self.expected_code},实际 {response.status_code}" check_200 = StatusCodeChecker(200) check_200(response_obj)

这种写法在复杂的断言链路中可以让代码非常简洁,不过刚入门时不用强行使用,了解即可。

5. 模块机制:拆分公共逻辑的正确姿势

5.1 模块是什么

模块就是一个.py文件。当你把class ApiClient写进api_client.py时,api_client就是一个模块。其他文件可以通过import api_clientfrom api_client import ApiClient使用它。

先看一个最小示例:

# 文件:config.py BASE_URL = "https://api.example.com" TIMEOUT = 5 # 文件:test_login.py import config def test_login(): print(config.BASE_URL)

模块的作用有两个层面:语义层面把功能分组,工程层面把命名空间隔离。如果没有模块隔离,你很难在一个大项目里同时使用两个都叫login的函数。

5.2if __name__ == '__main__'的底层逻辑

模块在被导入时,Python 解释器会把__name__变量设为模块名;当模块作为主程序直接运行时,则把__name__设为字符串'__main__'

所以下面这段代码是测试工程里的标准写法:

# 文件:api_client.py import requests class ApiClient: pass if __name__ == '__main__': # 只有直接运行 python api_client.py 时才执行 client = ApiClient("https://api.example.com") response = client.get("/health") print(response.status_code)

这样做的好处是:test_tools.pytest_login.py导入时,不会自动执行测试代码,只有主动运行python api_client.py时才会执行内部的自测逻辑。

5.3 模块的搜索路径与导入方式

Python 导入模块时会依次搜索:

  1. 当前脚本所在目录。
  2. PYTHONPATH环境变量中指定的目录。
  3. Python 安装目录下的site-packages等标准库路径。

如果找不到模块,会抛出ModuleNotFoundError。排查方式就是打印sys.path

import sys for path in sys.path: print(path)

导入方式选型:

# 方式一:导入整个模块 import config print(config.BASE_URL) # 方式二:从模块导入具体对象 from config import BASE_URL print(BASE_URL) # 方式三:导入多个对象 from config import BASE_URL, TIMEOUT # 方式四:起别名,解决命名冲突 import requests as http_client

注意不要使用from module import *这种导入方式。它会污染当前命名空间,让代码里出现大量不知道来源的变量,在测试工程里非常不利于排查问题。

5.4 常用内置模块在测试中的典型用法

Python 标准库里已经有很多直接支撑测试工作的模块。下面是面试和实际项目里出现频率最高的几个:

import os import json import logging from pathlib import Path from datetime import datetime # os:拼接路径、读取环境变量 project_dir = os.path.dirname(os.path.abspath(__file__)) report_dir = os.path.join(project_dir, "report") # pathlib:更现代的路径操作 project_path = Path(__file__).resolve().parent report_path = project_path / "report" # json:接口请求与响应转换 payload = {"username": "admin", "password": "123456"} json_str = json.dumps(payload, ensure_ascii=False) payload_dict = json.loads(json_str) # datetime:生成时间戳命名的测试报告 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") # logging:给测试代码加日志 logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") logging.info("开始执行登录接口测试")

内置模块不需要额外安装,是测试脚本中最常用的工具集。随着课程深入,后面还会接触到subprocessthreadingunittest.mock等模块在测试中的应用。

6. 包与测试项目目录:从零搭一套可维护的框架

6.1 包和普通目录的区别

包就是一个包含__init__.py文件的目录。__init__.py告诉 Python:这个目录是一个可以导入的包,而不是普通的文件夹。

一个典型的自动化测试项目结构如下:

auto_test/ ├── config/ │ ├── __init__.py │ └── setting.py ├── common/ │ ├── __init__.py │ ├── api_client.py │ ├── data_reader.py │ └── logger.py ├── data/ │ └── login_data.json ├── testcase/ │ ├── __init__.py │ ├── conftest.py │ └── test_login.py ├── report/ ├── logs/ └── main.py

如果目录里没有__init__.py,Python 3 在某些情况下仍能通过命名空间包导入,但为了让代码在各种环境下行为一致,强烈建议每个包目录都保留这个文件。

6.2 不同层级之间的导入写法

testcase/test_login.py里要导入common/api_client.py中的ApiClient类,正确写法是:

from common.api_client import ApiClient from config.setting import BASE_URL

注意,要以common.api_client方式导入,运行命令必须从项目根目录auto_test下执行:

python -m pytest testcase -v

6.3conftest.py的模块级共享

pytest 的conftest.py是一种特殊的模块,它存放 fixture,可以让同一目录及子目录下的多个测试模块共用。

import pytest @pytest.fixture() def api_client(): from common.api_client import ApiClient return ApiClient("https://api.example.com") @pytest.fixture() def login_token(api_client): response = api_client.post("/login", json={"username": "admin", "password": "123456"}) return response.json().get("token")

测试模块可以直接把api_clientlogin_token当作参数传入:

def test_user_info(login_token): assert login_token is not None

7. 实操:用类与模块完成一个登录接口测试

现在把前几节的知识串起来,完成一个真实的接口测试场景。假设有一个登录接口:

  • 地址:POST https://api.example.com/login
  • 请求体:{"username": "admin", "password": "123456"}
  • 成功响应:状态码 200,返回{"token": "xxx"}
  • 失败响应:状态码 401,返回{"message": "用户名或密码错误"}

7.1 第一步:封装 API Client 类

创建common/api_client.py

import requests class ApiClient: def __init__(self, base_url, timeout=10): self.base_url = base_url self.timeout = timeout self.session = requests.Session() def post(self, path, json=None, data=None): url = self.base_url + path response = self.session.post(url, json=json, data=data, timeout=self.timeout) return response def get(self, path, params=None): url = self.base_url + path response = self.session.get(url, params=params, timeout=self.timeout) return response def close(self): self.session.close() if __name__ == '__main__': client = ApiClient("https://api.example.com") resp = client.post("/login", json={"username": "admin", "password": "123456"}) print(resp.status_code, resp.json()) client.close()

7.2 第二步:使用 pytest 测试类组织用例

创建testcase/test_login.py

import pytest from common.api_client import ApiClient class TestLogin: @pytest.fixture(autouse=True) def setup(self): self.client = ApiClient("https://api.example.com") yield self.client.close() def test_login_success(self): payload = {"username": "admin", "password": "123456"} response = self.client.post("/login", json=payload) assert response.status_code == 200 assert response.json()["token"] def test_login_wrong_password(self): payload = {"username": "admin", "password": "wrong"} response = self.client.post("/login", json=payload) assert response.status_code == 401 assert response.json()["message"] == "用户名或密码错误"

这里的setup方法使用了 pytest 的 fixture 机制,在每个测试方法执行前后自动调用。注意文件命名必须以test_开头,测试类必须以Test开头,pytest 才能自动收集。

7.3 第三步:把测试数据独立成模块

直接写在用例里的测试数据属于硬编码。更好的方式是放到data/login_data.json

[ { "username": "admin", "password": "123456", "expected_code": 200, "expected_message": "登录成功" }, { "username": "admin", "password": "wrong", "expected_code": 401, "expected_message": "用户名或密码错误" } ]

common/data_reader.py中封装一个读取模块:

import json class JsonDataReader: @staticmethod def read(file_path): with open(file_path, "r", encoding="utf-8") as f: return json.load(f)

改造后的测试类:

import pytest from common.api_client import ApiClient from common.data_reader import JsonDataReader class TestLogin: @pytest.fixture(autouse=True) def setup(self): self.client = ApiClient("https://api.example.com") yield self.client.close() @pytest.mark.parametrize("case", JsonDataReader.read("data/login_data.json")) def test_login_with_data(self, case): payload = {"username": case["username"], "password": case["password"]} response = self.client.post("/login", json=payload) assert response.status_code == case["expected_code"]

这个版本已经具备数据驱动的雏形:用例逻辑不变,新增测试场景只需要在 JSON 文件里加一组数据。

7.4 第四步:统一入口模块

创建项目根目录下的main.py,让整个测试可以一键执行:

import pytest import os if __name__ == '__main__': report_dir = "report" os.makedirs(report_dir, exist_ok=True) pytest.main([ "testcase", "-v", "--html=report/report.html", "--self-contained-html" ])

运行方式:

python main.py

到这里,一条完整的链路已经闭环:ApiClient类负责请求,TestLogin类负责测试组织,JsonDataReader模块负责数据读取,main.py负责统一调度。

8. 常见问题与排查

类与模块相关的报错,占了测试新手排错的三分之一以上。下面是最高频的问题清单:

问题现象可能原因排查方式解决方案
ModuleNotFoundError: No module named 'common'运行目录不在项目根目录打印sys.path查看搜索路径回到根目录运行,或通过sys.path.insert(0, project_dir)临时解决
pytest 收集不到测试用例测试文件没有以test_开头,测试类没有以Test开头pytest --collect-only检查收集结果按 pytest 命名规范重命名
import导入了同名的另一个文件模块名和内置模块或第三方库冲突打印被导入模块的__file__属性修改模块名,不叫requests.pyjson.py这类名字
__init__方法没有self参数忘记写self查看报错提示的构造函数签名构造函数第一个参数写self
修改一个对象的属性后,其他对象也被改了把可变对象放在了类属性位置__init__里用self创建实例属性默认列表、字典等对象写入__init__
循环导入:a.py导入b.pyb.py又导入a.py模块之间依赖关系形成闭环查看报错中的 ImportError 栈把公共代码下沉到更低层模块,或延迟导入
直接运行模块时输出了测试代码没有使用if __name__ == '__main__'检查模块底部代码缩进把自测逻辑放进if __name__ == '__main__':代码块
AttributeError / 'TestLogin' object has no attribute 'client'fixture 或 setup 方法执行顺序异常添加日志确认 setup 是否执行检查 fixture 作用域,确认类内部 setup 是否被正确识别
两个模块里出现同名函数,后导入的覆盖了先导入的使用了from module import *检查是否还有*导入使用明确的名称或模块级导入

排查建议:遇到异常先看最后一行异常类型,再往上翻两行看具体代码,不要凭记忆猜测原因。

9. 测试框架中的类与模块最佳实践

9.1 命名规范

对象规范示例
类名大驼峰命名TestLoginApiClientJsonDataReader
方法名小写字母加下划线login_and_get_tokenread_test_data
模块名小写字母加下划线api_client.pydata_reader.py
测试文件test_开头test_login.pytest_user_info.py

9.2 设计要点

  1. 一个模块只做一件事。api_client.py里不要写登录用例,test_login.py里不要封装 requests 请求。
  2. 类应该面向"业务角色"设计。测试类对应"测试场景",页面对象类对应"页面操作",API 封装类对应"接口能力"。
  3. 优先使用实例方法,谨慎使用staticmethod。实例方法可以拿到对象状态,排查问题时更容易通过self追踪数据流。
  4. 测试用例和测试数据分离。用例只描述"做什么验证",数据由 JSON、YAML、Excel 等提供。
  5. 公共配置放入独立模块。如config/setting.py中的BASE_URLTIMEOUTDB_CONFIG等,避免在用例里散落硬编码数值。
  6. 日志模块单独封装。便于后续接入日志文件、日志轮转和测试报告。

9.3 面试中如何回答"类与模块在测试中的作用"

可以按下面这个思路组织回答:

类在测试中主要解决组织问题:测试类把同一功能的用例集中管理,API 封装类把请求层和用例层隔离,PO 模式把页面元素和测试逻辑解耦。模块解决的是工程问题:公共方法、配置、数据读取逻辑分别拆成独立文件,通过 import 组合使用。这样可以在团队协作中减少冲突、提高复用、方便维护。

10. 总结与下一步

第四课的两个关键字必须刻进记忆里:类是"数据和行为的组合体",模块是"代码的组织单元"。写自动化测试时,面向对象思想不是拿来装的,而是真实解决重复代码、数据混乱、项目难维护的问题。pytest 测试类、PO 模式、API 封装类的底层全部建立在类和模块之上。

建议你现在动手做三件事:

  1. 把 7.1 到 7.4 的代码敲一遍,跑通一个最小接口测试项目。
  2. data/login_data.json里加一组测试数据,观察用例数是否自动增长。
  3. 故意制造一个ModuleNotFoundError,再通过打印sys.path排查修复,把排错流程练熟。

这套系列下一课会进入 pytest 断言、fixture 作用域和测试报告生成。届时你会发现,今天学的类和模块会像地基一样支撑起整个进阶框架。建议把这一课的例子保存到本地练习目录,后面每学一个新知识点就回来改造一次代码,效果比单纯看课要好得多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 20:28:08

AI测试开发岗需求暴涨:2026秋招,高薪Offer都藏在这3个变化里

关注 霍格沃兹软件测试开发 公众号&#xff0c;回复「资料」, 领取人工智能测试开发技术合集室友拿了某大厂AI测试开发的Offer&#xff0c;月薪6万起步。隔壁实验室的师兄投了200份简历&#xff0c;面试通知全是"已过期"。这是2026年秋招的真实切片。我翻了牛客网最新…

作者头像 李华
网站建设 2026/9/2 20:23:56

MSComm32.ocx 未注册?原理、注册步骤与一键脚本全解析

简介&#xff1a;MSComm32.ocx控件注册文件包面向Visual Basic 6、VB.NET、Delphi等Windows桌面开发环境&#xff0c;解决串口通信中该控件缺失或未注册导致的运行错误&#xff0c;适用于工业控制、设备调试及上位机场景。包内共7个文件&#xff0c;总大小10.68MB&#xff0c;涵…

作者头像 李华
网站建设 2026/9/2 20:23:54

Office卸载工具与残留清理完整指南:从原理到高频报错排查

简介&#xff1a;Office卸载工具是一套专门用于彻底清理Office 2003、2007、2010残留组件的实用程序&#xff0c;面向因常规卸载卡顿、中断或残留导致新版本安装失败的IT维护人员及普通用户。压缩包内共4个文件&#xff0c;以3个MSI卸载组件和1个HTML操作说明为主&#xff0c;整…

作者头像 李华
网站建设 2026/9/2 20:18:23

万用表对比:优利德(UNI-T) | 胜利(VICTOR) | 彼赛(BSIDE)

一.总体对比一句话总结&#xff1a;要体系、精度、长期稳定 → 优利德 UNI-T要便宜、皮实、电工渠道方便修 → 胜利 VICTOR要功能多、彩屏酷、尝鲜 → 彼赛 BSIDE维度优利德 UNI-T胜利 VICTORBSIDE 彼赛品牌定位电子测量仪器&#xff0c;工程师向传统电工工具&#xff0c;大众走…

作者头像 李华
网站建设 2026/9/2 20:16:53

用AI复刻SaaS文档处理服务:从订阅制到Token计费实战

最近我一直在想一件事情&#xff1a;那些看起来“高大上”的 SaaS 工具&#xff0c;真的是靠技术壁垒收那么贵&#xff0c;还是只是把几个通用能力包装成了订阅&#xff1f;于是这次我做了一个试验&#xff1a;选了一款价格不低的订阅制文档处理 SaaS&#xff0c;不破解、不扒源…

作者头像 李华
网站建设 2026/9/2 20:15:44

从零搭建Spring Boot项目骨架:UNK20 Day1实战复盘

各位开发者朋友&#xff0c;大家好。最近在复盘一个很有意思的技术训练营项目“UNK20”&#xff0c;它的 Day1 课程是由 Simon Patterson 主讲的第七期内容&#xff08;编号 VII&#xff09;。这里先解释一下背景&#xff1a;UNK20 是一个偏实战的集中式学习项目&#xff0c;特…

作者头像 李华