当前位置:首页>python>python 013: Hypothesis 怎样帮你自动挖出边界 bug

python 013: Hypothesis 怎样帮你自动挖出边界 bug

  • 2026-07-02 21:27:36
python 013: Hypothesis 怎样帮你自动挖出边界 bug

别再只拿固定样例测代码:Hypothesis 怎样帮你自动挖出边界 bug

系列文章:Python 奇技淫巧 #013
很多测试之所以“总能通过”,并不是因为代码真的稳,而是因为你喂给它的输入太正常了:长度刚好、顺序理想、字符干净、数字不极端、状态变化也很规矩。这样的测试当然有价值,但它们经常只能证明“你手里这几个样例没问题”,证明不了“这段逻辑对一整类输入都靠谱”。Hypothesis 的厉害之处,就在于它把测试从“手工举例”升级成“自动探索输入空间”——你描述应该始终成立的性质,它负责自动生成样例、主动撞边界、缩小失败输入,最后把 bug 逼到一个最小可复现样例上。 这件事,对工具库、API 服务、数据清洗、AI 应用、状态机流程都很有杀伤力。


📌 为什么这篇值得写?

很多团队并不是不测,而是测法天然有盲区:

  • ❌ 样例全是“正常输入”,边界值、脏数据、极端组合没人覆盖
  • ❌ 测试函数写了不少,但本质上只是把 3 个案例复制成 10 个案例
  • ❌ 一旦要覆盖组合空间,测试数量指数膨胀,根本维护不过来
  • ❌ bug 真到了线上,回头一看才发现:缺的不是断言,而是输入探索
  • ❌ 某些逻辑只有在“多步操作”“特殊顺序”“很小但奇怪的输入”下才会出错

所以真正的问题不是:

“我还能再补几个测试样例?”

而是:

“我能不能描述一条应该始终成立的性质,然后让工具替我去撞那些我没想到的输入?”

这正是 Hypothesis 的价值。


🖼️ 先看图:Hypothesis 到底在替你做什么?

上面这张图是我自制的 SVG 信息图。SVG 本质上是用代码描述的矢量图,放大不糊、改字方便、适合版本管理,尤其适合技术文章里解释流程、结构和能力边界。像 Hypothesis 这种偏“测试方法升级”的工具,用 SVG 来讲会比截图更清楚。


🎯 Hypothesis 是什么?

Hypothesis 官方文档首页给它的定位非常直接:

Hypothesis is the property-based testing library for Python.

官方对它的进一步描述也很关键:你写的是“对某个输入范围内都应该成立的测试”,然后让 Hypothesis 自动去选择要检查哪些输入,包括你自己未必会主动想到的边界情况

这意味着它和传统“手写固定样例”的测试思路不太一样:

Hypothesis 最值得记住的几个能力点,大概是:

  • @given(...)
    :告诉测试“输入从哪里来”
  • hypothesis.strategies
    :声明数据生成策略
  • shrinking
    :失败后自动把输入缩成更小、更容易理解的反例
  • @settings(...)
    :控制样例数量、数据库重放、运行阶段等
  • RuleBasedStateMachine
    :用状态机方式探索多步操作 bug
  • 能直接和 pytestunittest 等常见测试方式协同

这里最重要的一句不是“它会随机造数据”,而是:

Hypothesis 不是随机测试玩具,而是一套“性质驱动 + 自动生成 + 最小反例收缩”的测试方法。


🆚 为什么固定样例总会漏掉边界 bug?

很多人最开始写测试,是这样想的:

def test_split_ok():
    assert split_into_batches([1, 2, 3, 4], 2) == [[1, 2], [3, 4]]


def test_split_tail():
    assert split_into_batches([1, 2, 3], 2) == [[1, 2], [3]]

这当然没错,但问题也很明显:

  • 你只检查了自己想到的两个输入
  • 你没有系统覆盖空列表、单元素、极大 size、极小 size 等边界
  • 如果 bug 藏在某个很奇怪但又很小的输入上,这类测试通常碰不到

而 Hypothesis 的思路是换个问法:

不去问“这两个样例结果对不对”,而去问“对于任意合法输入,这个函数有没有某些始终成立的性质?”

一旦你问对了问题,很多本来很难系统覆盖的边界,就能自动被扫出来。


1. 一个很典型的例子:批量切分函数明明看着没问题,为什么还是会漏数据?

来看一个非常常见的工具函数:把列表切成固定大小的小批次。

def split_into_batches(items: list[int], size: int) -> list[list[int]]:
    return [items[i : i + size] for i in range(0, len(items) - 1, size)]

这段代码乍一看很像真的,很多人甚至肉眼扫一遍都不一定立刻发现问题。但它其实有一个隐藏 bug:

  • 当列表长度比较特殊时,最后一个元素可能被悄悄漏掉

如果你手工写样例,很容易刚好写到几个“碰巧没暴露问题”的输入。更稳的做法是直接写性质:

这个函数至少该满足什么性质?

  1. 批次展平后,内容应该和原始输入完全一致
  2. 每个批次长度都不能超过 size
  3. 只要输入非空,批次里的每个子列表都不该是空的

对应的 Hypothesis 测试可以这样写:

from hypothesis import given, strategies as st


@given(
    items=st.lists(st.integers()),
    size=st.integers(min_value=1, max_value=20),
)
def test_split_into_batches_preserves_data(items, size):
    batches = split_into_batches(items, size)
    flattened = [x for batch in batches for x in batch]

    assert flattened == items
    assert all(len(batch) <= size for batch in batches)
    assert all(len(batch) > 0 for batch in batches)

这里真正妙的地方不在于语法,而在于你已经把测试目标从:

  • “验证 [1,2,3,4] 和 [1,2,3] 这两个例子”

升级成了:

  • “验证任意整型列表 + 任意合法批大小下,结果都必须满足这些性质”

如果这个实现真的有问题,Hypothesis 往往会很快给出一个失败输入,而且不满足于只给你一个巨大的脏例子,它还会继续 shrink

你最后看到的,很可能是这种级别的反例:

Falsifying example: test_split_into_batches_preserves_data(
    items=[0],
    size=1,
)

这就是真正让人上头的地方:

它不只是替你找 bug,还会努力把 bug 压缩成一个最容易理解、最容易复现的最小失败样例。

这比“随机扔一大堆数据,然后报一个你根本看不懂的失败案例”强太多了。


2. @given 和 strategy,才是 Hypothesis 的核心入口

Hypothesis 的写法并不复杂。最常见的入口就是:

  • @given(...)
  • from hypothesis import strategies as st

其中 @given 表示“把生成出来的数据喂给测试函数”,而 st 则是用来描述数据空间的。

比如这些都是很常用的策略:

一个非常重要的思维变化是:

你不是在“列出输入”,而是在“描述输入空间”。

这两者看起来只差一点,测试能力却差很多。


3. strategy 不是只能用内置类型:mapfiltercomposite 才是工程价值放大的地方

官方文档专门有一节讲 strategy 的适配方式,核心就是:

  • .map()
    :把已有生成值映射成你想要的结构
  • .filter()
    :过滤掉不需要的输入
  • @st.composite
    :自定义更复杂、带依赖关系的数据生成器

这部分很关键,因为真实项目里的输入通常不是“一个整数”这么简单,而是:

  • API payload
  • 聊天消息列表
  • 嵌套配置
  • 数据清洗前后的结构体
  • 带状态约束的对象组合

来看一个更贴近 AI 服务项目的例子:生成聊天请求。

from hypothesis import given, strategies as st


@st.composite
def chat_requests(draw):
    message_count = draw(st.integers(min_value=1, max_value=6))
    messages = []

    for _ in range(message_count):
        role = draw(st.sampled_from(["system", "user", "assistant"]))
        content = draw(st.text(min_size=1, max_size=200))
        messages.append({"role": role, "content": content})

    temperature = draw(
        st.floats(
            min_value=0,
            max_value=2,
            allow_nan=False,
            allow_infinity=False,
        )
    )
    return {"messages": messages, "temperature": temperature}


@given(chat_requests())
def test_prompt_builder_never_drops_message(payload):
    prompt = "\n".join(f"{m['role']}: {m['content']}" for m in payload["messages"])

    for msg in payload["messages"]:
        assert msg["content"] in prompt

这类测试的意义,不在于它能替代全部业务测试,而在于它可以帮你快速验证:

  • 构造器会不会丢消息
  • 某些特殊字符会不会把拼接逻辑搞坏
  • 空格、空行、非 ASCII 字符会不会触发你没想到的问题

这里有一个经验判断:

  • 业务样例测试
     负责证明“用户关心的场景能工作”
  • Hypothesis 性质测试
     负责证明“输入空间里那些奇怪角落不会轻易把你炸掉”

这两类测试不是互相替代,而是互相补位。


4. Hypothesis 和 pytest 不是竞争关系,而是非常适合一起用

Hypothesis quickstart 里明确提到:一个 Hypothesis 测试仍然是普通 Python 函数,所以 pytest 或 unittest 都可以像平常一样收集和运行它。

这点非常重要,因为它意味着:

  • 你不用换测试框架
  • 你不用推翻已有 pytest 体系
  • fixture、参数化、marker 这些能力依然能继续用

一个很自然的组合方式是:

import pytest
from hypothesis import given, strategies as st


@pytest.mark.slow
@given(st.lists(st.integers(), min_size=1, max_size=50))
def test_sorted_result_is_ordered(values):
    result = sorted(values)
    assert result == sorted(result)

如果你已经把项目测试组织在 pytest 下,那么引入 Hypothesis 最舒服的姿势不是“新开一套测试体系”,而是:

在已有 pytest 工程里,挑那些最容易出边界 bug 的函数,增量补上 property-based tests。

这比全盘迁移轻得多,也实用得多。


🗺️ 再看一张图:Hypothesis 的测试主路径是什么?

这张图可以把 Hypothesis 的核心工作流压缩成一句话:

先定义性质,再描述输入空间,交给 Hypothesis 自动生成样例;一旦失败,就收缩成最小反例,再回到 pytest/CI 里稳定复现。

它最值钱的地方,不是“随机生成很多数据”,而是把“生成 → 发现 → 收缩 → 复现”这条链完整打通了。


5. @settings 不只是调参数,它在决定你怎么把 Hypothesis 用进工程里

官方文档对 @settings(...) 的说明很实在:你可以用它控制:

  • 生成多少个样例(max_examples
  • 失败样例怎么重放
  • 哪些阶段启用(例如 replay、generate、shrink)
  • 输出详细程度
  • 是否启用数据库
  • 是否启用确定性运行(derandomize

最常见的用法大概长这样:

from hypothesis import given, settings, strategies as st


@settings(max_examples=300, deadline=None)
@given(st.text(), st.integers(min_value=1, max_value=50))
def test_chunking_roundtrip(text, size):
    chunks = [text[i : i + size] for i in range(0, len(text), size)]
    assert "".join(chunks) == text

这里的几个工程理解很重要:

官方文档还提到 settings profile。这件事我很建议在工程里用起来,因为很适合区分:

  • 开发环境:样例少一点,反馈更快
  • CI 环境:样例多一点,探索更深
  • 某些专项测试:单独配置数据库或更详细日志

如果你已经有 pytest 的测试分层,再配合 Hypothesis settings profile,整套体验会非常顺。


6. 当 bug 不在“单次输入”,而在“多步操作顺序”时,就该看 stateful testing 了

Hypothesis 官方文档里还有一个很强、但很多人没认真学的能力:stateful testing

官方对它的描述很准确:让 Hypothesis 不只选择“值”,还选择“动作”。也就是说,它不只是给你造输入,还会自动组合操作序列。

这对什么场景特别有用?

  • 缓存
  • 队列
  • 购物车
  • 权限状态切换
  • 会话生命周期
  • 数据结构实现(如栈、字典、索引)

核心入口通常是 RuleBasedStateMachine,再配合:

  • @rule(...)
    :定义可以执行的动作
  • @invariant(...)
    :定义每一步之后都必须成立的性质
  • Bundle
    :把前面步骤生成的数据传给后面规则

一个极简例子:

from hypothesis import strategies as st
from hypothesis.stateful import RuleBasedStateMachine, invariant, rule


class CounterMachine(RuleBasedStateMachine):
    def __init__(self):
        super().__init__()
        self.values = []
        self.total = 0

    @rule(x=st.integers(min_value=0, max_value=100))
    def append_value(self, x):
        self.values.append(x)
        self.total += x

    @invariant()
    def total_matches_values(self):
        assert self.total == sum(self.values)

当然,真实项目往往会比这复杂得多,但它提供的方向非常清楚:

如果 bug 来自“操作顺序”和“状态转换”,而不是一个静态输入,那么单纯样例测试就不够,stateful testing 会更像对的问题。

这也是很多缓存、任务调度、业务状态流转 bug 的高发区。


7. Hypothesis 最容易被用错的 4 个地方

误区 1:把它当“随机造数据器”

如果你只是想随机生成一堆输入,却没有描述明确性质,那测试价值会迅速下降。

正确思路是先问:

  • 哪个性质必须始终成立?
  • 哪个不变量不能被打破?
  • 哪种 round-trip 必须可逆?

误区 2:filter() 和 assume() 用太狠

官方文档也提醒过,过度过滤会让输入生成效率变差。很多时候,更好的方式是:

  • 优先选更合适的内置 strategy
  • 用 map() / composite 把结构一次性建对
  • 只在必要时用 filter()

误区 3:性质写得太弱

比如只断言“函数返回了 list”,这几乎没有测试价值。

更有用的性质通常是:

  • 顺序是否保持
  • 长度关系是否成立
  • 编码/解码是否可逆
  • 排序结果是否满足单调性
  • 聚合结果是否满足守恒关系

误区 4:一上来就全仓库铺开

最稳的做法永远是:

  1. 先挑最容易藏边界 bug 的纯函数或工具函数
  2. 再挑解析、清洗、转换、分块、归一化这类逻辑
  3. 最后才考虑状态机、多步骤业务流

Hypothesis 很强,但真正高效的用法不是“到处乱上”,而是优先砸那些你知道自己最容易漏边界的地方。


8. 一套很实用的落地顺序

如果你现在已经在用 pytest,我会建议这样落地:

第一步:先挑 1 个最容易翻车的工具函数

优先考虑:

  • 分页/切片
  • 字符串清洗
  • 配置解析
  • JSON 转换
  • 时间区间处理
  • 去重、排序、归并

第二步:先写“性质”,再写 strategy

不要先想“我要生成什么奇怪数据”,而是先想:

  • 结果和输入应该保持什么关系?
  • 哪个约束永远不能破?
  • 哪个 round-trip 必须成立?

第三步:在 pytest 里增量加入

例如只在 tests/property/ 或 tests/unit/ 里先放几条 property-based tests,不要一开始就推倒重来。

第四步:给本地和 CI 分别配 settings

  • 本地:反馈快一点
  • CI:覆盖深一点

第五步:遇到状态问题,再引入 stateful testing

别一开始就上状态机,但一旦你的 bug 主要出在流程顺序,那就别继续死磕静态样例了。


9. 我对 Hypothesis 的一个明确判断

很多人把测试能力理解成“样例写得够不够多”,但我越来越觉得,真正决定测试上限的,是你有没有能力从“样例思维”切到“性质思维”。

而 Hypothesis 恰好就在做这件事:

  • 它逼你定义不变量
  • 它帮你探索输入空间
  • 它帮你自动缩小失败输入
  • 它让很多“只能靠经验撞到”的边界 bug,变成可以稳定复现的问题

所以我更愿意这样定义它:

Hypothesis 不是帮你多写测试,而是帮你把测试从“举例说明”推进到“系统证明”。

这就是它真正值钱的地方。


10. 一个可以直接落地的最小模板

from hypothesis import given, strategies as st


def reverse_twice(text: str) -> str:
    return text[::-1][::-1]


@given(st.text())
def test_reverse_twice_roundtrip(text):
    assert reverse_twice(text) == text

如果你已经在用 pytest,直接执行:

pip install hypothesis pytest
pytest

接着你就可以把最容易藏边界 bug 的那几个函数,逐步改写成 property-based tests。


结语

学 Hypothesis,别只学 @given 的语法。

真正要学会的是:

  • 怎么把“业务直觉”改写成“可验证性质”
  • 怎么把“几个样例”升级成“一个输入空间”
  • 怎么利用 shrinking 快速定位最小失败样例
  • 怎么把它平滑接进 pytest 和 CI
  • 怎么在必要时把单步测试升级成 stateful testing

当你这样理解 Hypothesis,它就不再只是“自动造数据”,而是“帮你主动挖边界 bug 的测试引擎”。

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-03 22:54:42 HTTP/2.0 GET : https://f.mffb.com.cn/a/487236.html
  2. 运行时间 : 0.184695s [ 吞吐率:5.41req/s ] 内存消耗:4,809.45kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=6d08529739067a595ff28112c7e7a5b2
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.001050s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000869s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000307s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000363s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000475s ]
  6. SELECT * FROM `set` [ RunTime:0.000218s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000609s ]
  8. SELECT * FROM `article` WHERE `id` = 487236 LIMIT 1 [ RunTime:0.000704s ]
  9. UPDATE `article` SET `lasttime` = 1783090482 WHERE `id` = 487236 [ RunTime:0.001013s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 66 LIMIT 1 [ RunTime:0.000316s ]
  11. SELECT * FROM `article` WHERE `id` < 487236 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000448s ]
  12. SELECT * FROM `article` WHERE `id` > 487236 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000562s ]
  13. SELECT * FROM `article` WHERE `id` < 487236 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.000983s ]
  14. SELECT * FROM `article` WHERE `id` < 487236 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.000855s ]
  15. SELECT * FROM `article` WHERE `id` < 487236 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.003639s ]
0.186293s