How to Mock SQLite executemany When Batch Inserting in Python
Batch insert many rows into SQLite with executemany and mock the cursor for isolated tests.
Python code
41 linesimport sqlite3
from unittest.mock import Mock, patch
def insert_users(conn, users):
"""Insert multiple user records using executemany."""
cursor = conn.cursor()
cursor.executemany(
"INSERT INTO users (name, age) VALUES (?, ?)",
users
)
conn.commit()
return cursor.rowcount
if __name__ == "__main__":
# Create a real in-memory database for demonstration
conn = sqlite3.connect(":memory:")
conn.execute("CREATE TABLE users (name TEXT, age INTEGER)")
users = [
("Alice", 30),
("Bob", 25),
("Charlie", 35)
]
count = insert_users(conn, users)
print(f"Inserted {count} rows")
# Verify the data
rows = conn.execute("SELECT * FROM users ORDER BY name").fetchall()
print("Database contents:", rows)
# Now demonstrate mocking for testing
mock_conn = Mock()
mock_conn.cursor.return_value.executemany.return_value = Mock(rowcount=0)
with patch("__main__.insert_users", wraps=insert_users) as mocked_insert:
# Test with mock connection
result = mocked_insert(mock_conn, [("Test", 1)])
print(f"Mock result: {result}")
conn.close()
Output
Inserted 3 rows
Database contents: [('Alice', 30), ('Bob', 25), ('Charlie', 35)]
Mock result: 0
How it works
The insert_users function calls executemany on the connection's cursor, passing the SQL template and the list of tuples. The commit ensures all rows are saved. When testing, Mock replaces the connection and its cursor so no real database is needed. The patch context manager wraps the function to allow checking calls while using the mock. This isolates logic and avoids side effects.
Common mistakes
- Forgetting that `executemany` takes a list of tuples, not a tuple of tuples.
- Assuming `rowcount` is returned automatically without mocking the return value.
- Not calling `commit()` which leads to no rows in the actual database.
Variations
- Use `patch('module.insert_users')` to replace the entire function with a Mock instead of wrapping.
- Use a context manager `with mock_conn.cursor() as cursor` to avoid leaking cursors.
Real-world use cases
- Bulk-loading CSV data into a database for ETL pipelines.
- Seeding test databases with sample data quickly.
- Testing database functions in unit tests without a live connection.
Sponsored
More from Database scaling & optimization
- Approximate Count with HyperLogLog in Python medium
- B-Tree Insert and In-Order Traversal in Python hard
- Broadcast a Small Reference Table in Python easy
- Build a Full Text Search Index in Python medium
- Build a Partial Index Mock in Python for Database Filtering easy
- Composite index leftmost prefix in Python medium
Keep learning
Related tutorials and quizzes for this topic.