A minitest-compatible testing framework for mruby. It covers the core minitest API: test classes, assertions, spec DSL, and expectations.
mruby-minitest is an mrbgem that ports the essential parts of minitest to mruby:
- Minitest::Test with setup/teardown lifecycle
- Assertions: assert_equal, assert_raises, assert_nil, assert_match, assert_in_delta, assert_predicate, assert_operator, flunk, skip, pass, and all refute_* counterparts
- Spec DSL: describe/it blocks, before/after hooks, let/subject
- Expectations: must_equal, must_include, must_raise, must_match, wont_equal, wont_include, etc.
- Explicit runner: call
Minitest.run(ARGV)at the bottom of your test file (mruby does not haveat_exit, so no autorun) - Reporters: dot-based progress and summary output
# test/calculator_test.rb
class TestCalculator < Minitest::Test
def setup
@calc = 1
end
def test_adds
assert_equal 3, @calc + 2
end
end
Minitest.run(ARGV) || exit(1)Or spec-style:
describe "Array" do
it "includes elements" do
_([1, 2, 3]).must_include 2
end
it "is empty" do
_([]).must_be :empty?
end
end
Minitest.run(ARGV) || exit(1)Add to your mruby build config:
MRuby::Build.new("mruby-minitest") do |conf|
conf.toolchain
conf.gembox "default"
conf.gem github: "0x1eef/mruby-minitest", branch: "main"
conf.enable_debug
endDependencies are declared in mrbgem.rake. The only external
dependency is mruby-stringio (for capture_io / assert_output).
| Feature | Status |
|---|---|
| Minitest::Test with test_* discovery | ✅ |
| setup / teardown lifecycle | ✅ |
| assert / refute | ✅ |
| assert_equal / refute_equal | ✅ |
| assert_nil / refute_nil | ✅ |
| assert_raises | ✅ |
| assert_in_delta / refute_in_delta | ✅ |
| assert_match / refute_match | ✅ |
| assert_includes / refute_includes | ✅ |
| assert_predicate / refute_predicate | ✅ |
| assert_operator / refute_operator | ✅ |
| assert_respond_to / refute_respond_to | ✅ |
| assert_instance_of / refute_instance_of | ✅ |
| assert_kind_of / refute_kind_of | ✅ |
| assert_same / refute_same | ✅ |
| assert_empty / refute_empty | ✅ |
| assert_output / capture_io | ✅ (with stringio) |
| assert_silent | ✅ (with stringio) |
| assert_throws / catch | ✅ |
| skip / flunk / pass | ✅ |
| describe / it / specify | ✅ |
| before / after hooks | ✅ |
| let / subject | ✅ |
| Expectations (must_* / wont_*) | ✅ |
| Minitest.run(ARGV) | ✅ |
| SEED / --seed / --verbose / --name | ✅ |
| Feature | Reason |
|---|---|
| Auto-run (at_exit) | mruby does not have at_exit; call Minitest.run(ARGV) |
| Parallel execution | No Thread in mruby |
| Diff output | Needs Tempfile + external diff |
| Plugin auto-discovery | No Rubygems |
| INFO signal handler | No Signal/trap in mruby |
| Marshal-based exception sanitization | No Marshal in mruby |
| Bisect / Sprint / Server | Niche features |
| Benchmark | Separate gem (mruby-benchmark exists) |
| Pride output | Pure cosmetic, could add easily |
I wanted a familiar test framework to write tests for mruby-llm and minitest appeared to be a good candidate. The tests for llm.rb are written in RSpec, and porting those tests to mruby-minitest is more or less straight forward.
I used relay.app and DeepSeek v4 to analyze both the minitest and mruby repositories over a local Forgejo MCP server. The analysis determined what could and couldn't be ported to mruby, and afterwards it created a repository that implemented the port. It wasn't perfect but served as a good foundation.
No new code was generated per se, it was more like copying the existing parts of minitest that were portable and dropping what wasn't. The code itself is minitest, just optimized to include only those parts that can work on mruby.
- toplevel: add
contextas an alias ofdescribe - DSL: add
DSL#{describe,context}
MIT