ruby/ruby
Testing
Ruby has more test infrastructure than most languages — partly because behaviour matters across implementations (CRuby, JRuby, TruffleRuby) and partly because thirty years of language history has produced a lot of compatibility surface to defend.
The four test layers
| Layer | Directory | Runner | Purpose |
|---|---|---|---|
| Bootstrap test | bootstraptest/ |
bootstraptest/runner.rb (via make btest) |
Smoke tests; runs against a freshly-built miniruby very early in make. Tests core VM mechanics. |
| Basic test | basictest/ |
make test-basic |
A handful of pass/fail scripts the binary must succeed on before the full suite is even attempted. |
| Test suite | test/ruby/, test/<gem>/ |
test-unit (vendored, tool/test/runner.rb) |
The main CRuby test corpus. Hundreds of files, thousands of tests. |
| Behaviour spec | spec/ruby/ |
MSpec (vendored under spec/mspec/) |
The cross-implementation ruby/spec. Documents observable language behaviour, run by JRuby and TruffleRuby too. |
A typical run order from a fresh build:
make btest # ~30s, lots of bytecode/VM tests
make test-basic # ~5s
make test-all # 5-15 min depending on hardware
make test-spec # 5-15 min
make check # all of the abovemake exam adds linting and leak checks on top of make check.
Running one file
make test-all and make test-spec accept a TESTS argument:
make test-all TESTS="test/ruby/test_array.rb"
make test-all TESTS="-n /test_each_with_index/ test/ruby/test_array.rb"
make test-spec MSPECOPT="spec/ruby/core/array/each_spec.rb"For ad-hoc runs without going through make:
./tool/runruby.rb test/ruby/test_array.rb
./tool/runruby.rb spec/mspec/bin/mspec spec/ruby/core/array/each_spec.rbBootstrap tests
bootstraptest/ files use a tiny DSL:
assert_equal 'Array', %q{ [].class }
assert_normal_exit %q{ raise "boom" rescue nil }These run with the smallest possible Ruby (sometimes miniruby) and are often the first to break when VM internals change. They're also the fastest signal — many maintainers run make btest after every edit to vm_*.c, compile.c, or gc.c.
test/ruby and test/
Files use Test::Unit::TestCase:
require 'test/unit'
class TestArray < Test::Unit::TestCase
def test_basic_each
a = []
[1, 2, 3].each { |x| a << x }
assert_equal [1, 2, 3], a
end
endConvention: one test_<topic>.rb per source area. test/ruby/test_compile.rb exercises the bytecode compiler; test/ruby/test_yjit.rb exercises YJIT; etc.
tool/test/runner.rb and tool/lib/test/unit.rb extend Test::Unit with multi-process parallelism and Ruby-specific reporters.
ruby/spec
spec/ruby/ is a vendored mirror of the cross-implementation ruby/spec project. Specs document observable behaviour:
describe "Array#each" do
it "yields each element" do
a = []
[1, 2, 3].each { |x| a << x }
a.should == [1, 2, 3]
end
endWhen you change observable Ruby semantics, you typically need both a test/ruby/ test (defends CRuby's specific behaviour) and a spec/ruby/ spec (documents the language's behaviour). The spec change should be PRed both here and at ruby/spec upstream.
spec/.excludes/, spec/.excludes-mmtk/, and spec/.excludes-zjit/ exclude specs that don't apply to specific configurations. If a JIT or GC variant breaks a spec deliberately, add an exclusion file with a # reason comment.
Benchmarks
benchmark/ contains microbenchmarks, used by:
make benchmark— runs a curated subset.- The external yjit-bench repo for end-to-end workloads (Optcarrot, Liquid, etc.).
When tuning hot paths, run the affected benchmarks before and after with benchmark-driver (make benchmark BENCH_RUBY=./ruby BENCH_FILE=benchmark/foo.yml).
CI
.github/workflows/ defines the production CI. Notable workflows:
ubuntu.yml,macos.yml,windows.yml,mingw.yml— cross-platform builds.yjit-ubuntu.yml,zjit-ubuntu.yml,yjit-macos.yml— JIT-focused configurations.mmtk.yml— runstest-all/test-specwith the MMTk GC.bsdl.yml— checksBSDLlicense file.compilers.yml— tests building under multiple GCC/Clang versions.prism.yml— runs the suite with the Prism parser as the default.
CI is the source of truth for "what is expected to pass". A PR that turns a workflow red won't be merged.
Coverage and leak checking
tool/test-coverage.rbandtool/run-lcov.rbproduce LCOV reports for the C code.make examincludesmake leaked-globals(checks symbol leaks in the built binary).make test-rubyspecis an alias formake test-spec.
Adding a new test
For a new method Array#sample_with_seed:
- Add a
Test::Unittest intest/ruby/test_array.rbcovering happy paths and edge cases. - Add a spec under
spec/ruby/core/array/sample_with_seed_spec.rb. - If the change is YJIT-relevant, add a regression test in
test/ruby/test_yjit.rb.
For a new public C API:
- Add a documented declaration in the relevant
include/ruby/header. - Add C tests under
ext/-test-/(the-test-extension is built only duringmake test-all).
Excluded tests
Some tests are skipped on specific platforms or configurations:
spec/.excludes/— generic spec exclusions.tool/rbs_skip_tests/tool/rbs_skip_tests_windows— skip flaky RBS tests on Windows.test/excludes/(per default-gem subdirectories) — skip a particular known-failing test from a vendored gem.
When you add an exclusion, leave a comment explaining the failure mode.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.