Why aren't my Minitest tests being run in parallel?

Hubro Source

I just recently figured out that my Minitest test cases can run in parallel. All I had to do was

require "minitest/hell"

and so I did. Unfortunately, my tests run exactly like before. Everything passes and it takes exactly as much time as it usually does. I checked htop while running my test suite, and only one core is utilized.

I set a breakpoint in a random test to check if the tests were actually set to run in parallel:

(byebug) Minitest::Test.test_order
:parallel

So what's going on?


My first assumption was that Minitest counts the amount of CPU cores when deciding how many processes to spawn. I had multiple physical processors (in a virtual machine) but just 1 core per processor. I have changed my VPS to having two physical processors, each with 4 cores, and my tests still aren't being run in parallel.

$ lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                8
On-line CPU(s) list:   0-7
Thread(s) per core:    1
Core(s) per socket:    4
Socket(s):             2
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 62
Stepping:              4
CPU MHz:               2600.000
BogoMIPS:              5200.00
Hypervisor vendor:     VMware
Virtualization type:   full
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              20480K
NUMA node0 CPU(s):     0-7
rubyparallel-processingminitest

Answers

answered 4 years ago severin #1

Minitest uses threads and not processes for parallel test execution.

Since MRI (the standard Ruby interpreter) has a Global Interpreter Lock only one thread can be executed at a time. Therefore your tests do not run in parallel when using MRI.

You can get you tests to run in parallel by using a Ruby interpreter that supports concurrent threads like JRuby or Rubinius.

Read this article for more details.

answered 4 years ago joelparkerhenderson #2

To run tests in parallel, you either need a Ruby version that enables parallel execution (e.g. JRuby), or you can use simple shell commands to launch multiple minitest runs.

For example, use gnu parallel:

find test -type f | parallel --dry-run  bundle exec rake test TEST={}

(The dry-run flag is so you can see what's happening before you run it; omit the dry-run flag when you're satisfied the commands will do what you want.)

The overhead of bundle exec and rake are very high. The core advantage of the parallel execution is to ensure your tests behave correctly -- i.e. the core advantage is not speed. If you use parallel, you will likely want to try spork which keeps a pre-warmed app ready.

answered 4 years ago Chris Kottom #3

severin's answer about MRI not being able to execute in parallel because of the GIL is correct. (Disclaimer: I wrote the article he links to.) The language gets a little fuzzy in many writeups, but you can read this article for a very straightforward description.

If you're still interested in running tests in parallel and can't change Ruby interpreters, take a look at the parallel_tests gem as an alternative for doing that, albeit with some limitations.

comments powered by Disqus