How to Mock Redis EXPIRE, TTL, and PERSIST in Python

A lightweight in-memory MockRedis class that simulates Redis key expiration, TTL, and persist behavior for tests and local development.

Medium Python 3.9+ Aug 9, 2026 Caching & Redis 14 views 0 copies

Python code

54 lines
Python 3.9+
import time

class MockRedis:
    def __init__(self):
        self._store = {}
        self._expiry = {}

    def set(self, key, value):
        self._store[key] = value
        self._expiry.pop(key, None)
        return True

    def expire(self, key, ttl_seconds):
        if key not in self._store:
            return False
        self._expiry[key] = time.time() + ttl_seconds
        return True

    def persist(self, key):
        if key not in self._store:
            return False
        if key in self._expiry:
            del self._expiry[key]
            return True
        return False

    def ttl(self, key):
        if key not in self._store:
            return -2
        if key not in self._expiry:
            return -1
        remaining = int(self._expiry[key] - time.time())
        return max(0, remaining)

    def get(self, key):
        if key not in self._store:
            return None
        expire_at = self._expiry.get(key)
        if expire_at is not None and time.time() > expire_at:
            del self._store[key]
            del self._expiry[key]
            return None
        return self._store[key]


if __name__ == "__main__":
    r = MockRedis()
    r.set("session", "abc123")
    print("TTL after set:", r.ttl("session"))
    print("Expire result:", r.expire("session", 5))
    print("TTL after expire:", r.ttl("session"))
    print("Persist result:", r.persist("session"))
    print("TTL after persist:", r.ttl("session"))
    print("GET value:", r.get("session"))

Output

stdout
TTL after set: -1
Expire result: True
TTL after expire: 5
Persist result: True
TTL after persist: -1
GET value: abc123

How it works

The MockRedis stores keys in a dictionary alongside a separate expiry map. set clears any prior expiry for the key. expire records an absolute timestamp using time.time() plus the TTL. persist removes the key from the expiry map, causing ttl to return -1 as Redis does. get proactively checks whether the expiry timestamp has passed and deletes the key on access. Using a mock like this lets you test TTL logic without hitting a real Redis server.

Common mistakes

  • Forgetting that `ttl` returns -1 for persistent keys, not 0.
  • Not deleting the expiry entry on `set`, causing stale TTL data.
  • Using the TTL value directly instead of an absolute timestamp, breaking long-running tests.
  • Assuming `persist` returns False for keys without TTL instead of True.

Variations

  1. Use `freezegun` to freeze `time.time()` for deterministic TTL tests.
  2. Subclass `unittest.mock.Mock` and patch Redis methods instead of building a full class.
  3. Use the `fakeredis` third-party library for a more complete Redis mock with Lua script support.

Real-world use cases

  • Unit-testing session management code that relies on Redis TTL without spinning up a server.
  • Developing locally against a Redis-like interface when Docker or Redis is unavailable.
  • Simulating cache expiry behavior in integration tests to verify cache-miss and refresh paths.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Caching & Redis

Related tutorials and quizzes for this topic.