BSD 3-Clause "New" or "Revised" License

技术解读

以下内容由 GitRead 中文社区 编辑团队基于项目 README 与官方资料整理, 结合中文开发者的常见使用场景补充技术选型建议。具体以项目官方文档为准。

深度技术分析:cunla/fakeredis-py

项目背景与痛点

在开发涉及 Redis 的应用时,我们面临着一个常见问题:测试环境往往需要一个完整的 Redis 服务,这无疑增加了开发和测试的复杂性。fakeredis-py 就是为了应对这一问题而生,它完全兼容 redis-py,可以模拟 Redis 的 API 调用,却无需运行 Redis 服务。这使得它特别适用于测试环境,让你能够在不依赖实际存储服务的情况下,进行代码的开发与验证。

核心技术揭秘

fakeredis-py 的设计巧妙地实现了 Redis 的API接口,使其在纯 Python 环境下也能运行。它通过一个简单的对象模型来映射 Redis 的数据结构,包含了常见的 Redis 命令,如 SET, GET, LPUSH, RPUSH, 等等。下图简单展示了它的数据流和核心架构:

graph TD A[用户请求] --> B{"参数校验"} B -->|"校验通过"| C[执行命令] C --> D[更新内存存储] D --> E[返回结果] B -->|"校验失败"| F[返回错误]

每个请求首先经过参数校验,确保指令和参数的正确性。通过校验后,将调用特定的 Redis 命令,处理请求,并更新内存中的存储结构。处理完请求后,返回结果或抛出错误。这样的实现方式使得 fakeredis-py 在测试阶段的各环节都可以保持逻辑的一致性,这也是它能够与 redis-py 无缝对接的关键所在。

功能亮点与差异

相较于其他 Redis 模拟库,fakeredis-py 的一个显著优势在于其完全兼容 redis-py 的 API。这意味着你不再需要为测试环境和生产环境编写不同的代码,这一特性在开发和维护过程中,为开发者节省了大量的时间。此外,fakeredis-py 完全基于 Python 内存进行数据操作,因此具备更高的性能,在测试环境中尤其适合进行高频率的操作测试。

应用场景与落地建议

在生产环境中,虽然 fakeredis-py 不能替代真实的 Redis 服务,但在开发、集成和单元测试阶段,它能够减少资源依赖和环境配置的复杂性,减少了出错可能性。它适用于那些需要测试 API 调用正确性,而不关心实际数据存储逻辑的场景。当然,对于复杂的业务逻辑,依然推荐使用真实的 Redis 服务进行测试,但 fakeredis-py 依然是一个简化开发过程、提升测试效率的重要工具。

综合评价

fakeredis-py 虽然小巧,但在开发和测试中的作用不容小觑。它极大地提升了开发效率,减少了对实际 Redis 服务的依赖,使得开发者能够在依赖最少的情况下,验证代码的正确性。唯一的缺点是在处理较大数据集时,由于数据完全存储于内存中,可能会面临性能瓶颈。但在绝大多数的测试用例中,这种实现方式都是非常合适的。如果是需要频繁操作 Redis 的内部业务逻辑开发,这无疑是一个强大的伴侣。

关于

GitHub 原始描述(英文)

Implementation of Redis API in python without having a server running. Fully compatible with using redis-py.

描述取自 GitHub 官方 API,保持仓库作者书写的原文。

简要分析

热度分
1048
价值分
335
活跃状态
活跃

语言占比

Python

Release

README

fakeredis

A fast, pure-Python implementation of the Redis protocol — no server required.

PyPI version CI Coverage Downloads Python versions License Open Source Helpers

Documentation · Supported commands · Changelog · Sponsor


fakeredis is a drop-in replacement for redis-py and valkey-py that runs entirely in-memory. Write tests that depend on Redis, Valkey, DragonflyDB, KeyDB, or KiviDB — without spinning up a real server, a container, or a network connection.

import fakeredis

r = fakeredis.FakeStrictRedis()
r.set("foo", "bar")
r.get("foo")  # b'bar'

That’s it. No server to install, no port to manage, no teardown.

✨ Why fakeredis?

  • 🚀 Zero setup — no Redis server, Docker, or network required. Pure Python.
  • 🔌 Drop-in compatible — same API as redis.Redis and redis.asyncio.Redis.
  • ⚡ Fast & isolated — in-memory, so tests run quickly and start from a clean slate.
  • 🧩 Multi-backend — emulate Redis, Valkey, DragonflyDB, KeyDB, or KiviDB, and pin a specific server version.
  • 📦 Redis Stack support — JSON, Bloom/Cuckoo filters, Count-Min Sketch, Top-K, T-Digest, TimeSeries, and vector sets.
  • 🤝 Share or isolate state — one shared in-memory server across clients, or independent servers per test.
  • 🌐 Real TCP mode — expose the fake server over a socket with TcpFakeServer, for clients you can’t inject.

📥 Installation

pip install fakeredis

Optional extras enable additional command families:

pip install "fakeredis[lua]"          # EVAL / EVALSHA scripting
pip install "fakeredis[json]"         # JSON.* commands
pip install "fakeredis[bf]"           # Bloom / Cuckoo / Count-Min / Top-K filters
pip install "fakeredis[probabilistic]"  # alias for the probabilistic filters
pip install "fakeredis[valkey]"       # Valkey client compatibility
pip install "fakeredis[digest]"       # DIGEST and DELEX IFDEQ / IFDNE (XXH3 digests)
pip install "fakeredis[vectorset]"    # vector set (V*) commands, Python 3.11+

🚀 Quickstart

Use it like redis.Redis:

import fakeredis

r = fakeredis.FakeStrictRedis()
r.lpush("queue", "a", "b", "c")
r.lrange("queue", 0, -1)  # [b'c', b'b', b'a']

Share one in-memory server between clients:

server = fakeredis.FakeServer()
r1 = fakeredis.FakeStrictRedis(server=server)
r2 = fakeredis.FakeStrictRedis(server=server)

r1.set("greeting", "hello")
r2.get("greeting")  # b'hello' — same underlying data

Async is supported too:

import fakeredis


async def main():
    r = fakeredis.FakeAsyncRedis()
    await r.set("foo", "bar")
    await r.get("foo")  # b'bar'

Pin a server type and version:

# Behave like Redis 6 — which is what KeyDB is compatible with...
r = fakeredis.FakeStrictRedis(version=6)
# ...or like Valkey, DragonflyDB or KiviDB
r = fakeredis.FakeStrictRedis(server_type="valkey")
r = fakeredis.FakeStrictRedis(server_type="dragonfly")
r = fakeredis.FakeStrictRedis(server_type="kividb")

Using it in tests (pytest)

import pytest
import fakeredis


@pytest.fixture
def redis_client():
    return fakeredis.FakeStrictRedis()


def test_cache_set(redis_client):
    redis_client.set("user:1", "alice")
    assert redis_client.get("user:1") == b"alice"

🌐 TCP server mode

The fake clients above only help when you can hand one to the code under test. When the code opens its own connection — or isn’t Python at all — TcpFakeServer serves the same in-memory server over a real TCP socket, so anything that speaks the Redis protocol can connect to it:

from threading import Thread

import redis
from fakeredis import TcpFakeServer

server = TcpFakeServer(("127.0.0.1", 6379), server_type="redis")
thread = Thread(target=server.serve_forever, daemon=True)
thread.start()

r = redis.Redis(host="127.0.0.1", port=6379)  # a regular client, not a fake one
r.set("foo", "bar")
r.get("foo")  # b'bar'

# When you are done:
r.close()
server.shutdown()
server.server_close()
thread.join()
  • Any client — redis-py, valkey-py, redis-cli, or a client in another language. All connections share one FakeServer, so they see the same data.
  • RESP2 and RESP3 — connections start in RESP2 and switch when the client sends HELLO 3, as with a real server. Pub/sub and blocking commands work over the socket too.
  • Server type and version — pass server_type ("redis", "valkey", "dragonfly", "kividb") and server_version (defaults to (8, 0)), e.g. TcpFakeServer(address, server_type="valkey", server_version=(8, 1)).
  • Free port — bind to port 0 to let the OS choose one, then read it back from server.server_address.

TcpFakeServer is a standard-library ThreadingTCPServer, handling each client connection on its own thread. It is meant for tests and local development, not as a production Redis replacement.

See the official documentation for the full list of supported commands and configuration options.

fakeredis-py is developed and maintained for free. If it saves you time, please consider becoming a sponsor — it directly supports continued development.

🤝 Contributing

Contributions are welcome! Check out the contributing guide and the open issues to get started.

评论

暂无评论