Ramp's engineering team tackled 20-minute Python CI test times through three approaches: restructuring database setup to enable higher parallelism with pytest-xdist (doubling machine size and halving test times), preserving the local test database between runs to save 10-30 seconds per run, and building a custom incremental pytest plugin that uses git diffs and sys.settrace (instead of coverage.py) to run only tests affected by changed code. The incremental runner executes 30-40% of the test suite and catches ~90% of failures in a few minutes. The post includes implementation details on inheritance chain traversal to handle SQLAlchemy model changes that coverage-based approaches miss, and honestly reflects that the incremental runner was a great learning experience but not something they'd invest in again given the complexity.

11m read timeFrom builders.ramp.com
Post cover image
Table of contents
Why do I care about test times?#1 Support higher concurrency.#2 Skip redundant initialization work.#3 Prioritize testing things that have changed.
2 Impressions