DEV Community

Cover image for Process-based parallel execution of plain Minitest tests
Erik Madsen
Erik Madsen

Posted on • Edited on

Process-based parallel execution of plain Minitest tests

I started work on a new gem today.

When I created my previous gem, churn_vs_complexity, I decided to use the new and exciting test library Tldr because of its philosophy of fast test suites.

While the experience of using that tool was nice overall, there were times where I got a bit of friction from its slightly unpolished current state (in fairness, no version 1.0.0 has been released yet) and the fact that it's not extensively used by the community.

In my new gem I wanted to see if I could use Minitest but keep the same, albeit less draconian, focus on speed of execution.

One thing I wanted to keep from Tldr was process based parallel execution from the onset of building my test suite.

My understanding is that Minitest has some built-in support for concurrently running tests, but it's thread based, so the Global Interpreter Lock (in runtimes that have one) will mean that the Ruby code will not be executing in parallel. It could still give you a performance boost if your tests perform I/O.

But I want the real deal. I need process-based concurrency so that my Ruby code can also execute in parallel.

I had a chat with my AI about how I could go about this, and it gave me a lot completely wrong answers with the utmost confidence. So after a while I decided I had to go back to attempting to be competent myself.

You might remember that Rails introduced built-in concurrent testing in version 7 for the Rails flavour of Minitest where test cases inherit from ActiveSupport::TestCase.

That particular class has too many batteries included for my use case, but I wanted to see if I could reuse ActiveSupport's way of instrumenting Minitest for parallelism.

After a bit of tinkering and reading the source code of ActiveSupport::TestCase, I found the solution I was looking for. It obviously requires ActiveSupport as a test dependency, but configuration-wise it's nice and lightweight.

I published the approach in the following GitHub Gist, and I'll likely reuse this pattern in other gems. Maybe it'll be useful for you as well.

Here's some example output of running rake test where we can see the parallelism in effect:

Running 2 tests in parallel using 10 processes
Run options: --seed 46661

# Running:

..

Finished in 0.211560s, 9.4536 runs/s, 9.4536 assertions/s.
Enter fullscreen mode Exit fullscreen mode

Top comments (0)