Minitest
minitest provides a complete suite of testing facilities supporting TDD, BDD, and benchmarking.
Install / Use
/learn @minitest/MinitestREADME
= minitest/{test,spec,benchmark}
home :: https://minite.st/ code :: https://github.com/minitest/minitest bugs :: https://github.com/minitest/minitest/issues rdoc :: https://docs.seattlerb.org/minitest clog :: https://github.com/minitest/minitest/blob/master/History.rdoc emacs:: https://github.com/arthurnn/minitest-emacs vim :: https://github.com/vim-test/vim-test
== DESCRIPTION:
minitest provides a complete suite of testing facilities supporting TDD, BDD, and benchmarking.
"I had a class with Jim Weirich on testing last week and we were
allowed to choose our testing frameworks. Kirk Haines and I were
paired up and we cracked open the code for a few test
frameworks...
I MUST say that minitest is *very* readable / understandable
compared to the 'other two' options we looked at. Nicely done and
thank you for helping us keep our mental sanity."
-- Wayne E. Seguin
minitest/test is a small and incredibly fast unit testing framework. It provides a rich set of assertions to make your tests clean and readable.
minitest/spec is a functionally complete spec engine. It hooks onto minitest/test and seamlessly bridges test assertions over to spec expectations.
minitest/benchmark is an awesome way to assert the performance of your algorithms in a repeatable manner. Now you can assert that your newb co-worker doesn't replace your linear algorithm with an exponential one!
minitest/pride shows pride in testing and adds coloring to your test output. I guess it is an example of how to write IO pipes too. :P
minitest/test is meant to have a clean implementation for language implementors that need a minimal set of methods to bootstrap a working test suite. For example, there is no magic involved for test-case discovery.
"Again, I can't praise enough the idea of a testing/specing
framework that I can actually read in full in one sitting!"
-- Piotr Szotkowski
Comparing to rspec:
rspec is a testing DSL. minitest is ruby.
-- Adam Hawkins, "Bow Before MiniTest"
minitest doesn't reinvent anything that ruby already provides, like: classes, modules, inheritance, methods. This means you only have to learn ruby to use minitest and all of your regular OO practices like extract-method refactorings still apply.
== FEATURES/PROBLEMS:
- minitest/autorun - the easy and explicit way to run all your tests.
- minitest/test - a very fast, simple, and clean test system.
- minitest/spec - a very fast, simple, and clean spec system.
- minitest/benchmark - an awesome way to assert your algorithm's performance.
- minitest/pride - show your pride in testing!
- minitest/test_task - a full-featured and clean rake task generator.
- Incredibly small and fast runner, but no bells and whistles.
- Written by squishy human beings. Software can never be perfect. We will all eventually die.
== RATIONALE:
See design_rationale.rb to see how specs and tests work in minitest.
== SYNOPSIS:
Given that you'd like to test the following class:
class Meme def i_can_has_cheezburger? "OHAI!" end
def will_it_blend?
"YES!"
end
end
=== Unit tests
Define your tests as methods beginning with +test_+. Use {assertions}[/minitest/Minitest/Assertions.html] to test for results or state.
require "minitest/autorun"
class TestMeme < Minitest::Test def setup @meme = Meme.new end
def test_that_kitty_can_eat
assert_equal "OHAI!", @meme.i_can_has_cheezburger?
end
def test_that_it_will_not_blend
refute_match /^no/i, @meme.will_it_blend?
end
def test_that_will_be_skipped
skip "test this later"
end
end
=== Specs
Use {expectations}[/minitest/Minitest/Expectations.html] to check results or state. They must be wrapped in a value call (eg +_+).
require "minitest/autorun"
describe Meme do before do @meme = Meme.new end
describe "when asked about cheeseburgers" do
it "must respond positively" do
_(@meme.i_can_has_cheezburger?).must_equal "OHAI!"
end
end
describe "when asked about blending possibilities" do
it "won't say no" do
_(@meme.will_it_blend?).wont_match /^no/i
end
end
end
For matchers support check out:
- https://github.com/wojtekmach/minitest-matchers
- https://github.com/rmm5t/minitest-matchers_vaccine
=== Benchmarks
Add {benchmarks}[/minitest/Minitest/Benchmark.html] to your tests.
optionally run benchmarks, good for CI-only work!
require "minitest/benchmark" if ENV["BENCH"]
class TestMeme < Minitest::Benchmark # Override self.bench_range or default range is [1, 10, 100, 1_000, 10_000] def bench_my_algorithm assert_performance_linear 0.9999 do |n| # n is a range value @obj.my_algorithm(n) end end end
Or add them to your specs. If you make benchmarks optional, you'll need to wrap your benchmarks in a conditional since the methods won't be defined. In minitest 5, the describe name needs to match <tt>/Bench(mark)?$/</tt>.
describe "Meme Benchmark" do if ENV["BENCH"] then bench_performance_linear "my_algorithm", 0.9999 do |n| 100.times do @obj.my_algorithm(n) end end end end
outputs something like:
Running benchmarks:
TestBlah 100 1000 10000 bench_my_algorithm 0.006167 0.079279 0.786993 bench_other_algorithm 0.061679 0.792797 7.869932
Output is tab-delimited to make it easy to paste into a spreadsheet.
=== Running Your Tests
Ideally, you'll use a rake task to run your tests (see below), either piecemeal or all at once. BUT! You don't have to:
% ruby -Ilib:test test/minitest/test_minitest_test.rb
Run options: --seed 37685
# Running:
...................................................................... (etc)
Finished in 0.107130s, 1446.8403 runs/s, 2959.0217 assertions/s.
155 runs, 317 assertions, 0 failures, 0 errors, 0 skips
There are runtime options available, both from minitest itself, and also provided via plugins. To see them, simply run with +--help+:
% ruby -Ilib:test test/minitest/test_minitest_test.rb --help
minitest options:
-h, --help Display this help.
-s, --seed SEED Sets random seed. Also via env. Eg: SEED=n rake
-v, --verbose Verbose. Show progress processing files.
-n, --name PATTERN Filter run on /regexp/ or string.
-e, --exclude PATTERN Exclude /regexp/ or string from run.
Known extensions: pride, autotest
-p, --pride Pride. Show your testing pride!
-a, --autotest Connect to autotest server.
=== Rake Tasks
You can set up a rake task to run all your tests by adding this to your Rakefile:
require "minitest/test_task"
Minitest::TestTask.create # named test, sensible defaults
# or more explicitly:
Minitest::TestTask.create(:test) do |t|
t.libs << "test"
t.libs << "lib"
t.warning = false
t.test_globs = ["test/**/*_test.rb"]
end
task :default => :test
Each of these will generate 4 tasks:
rake test :: Run the test suite.
rake test:cmd :: Print out the test command.
rake test:isolated :: Show which test files fail when run separately.
rake test:slow :: Show bottom 25 tests sorted by time.
=== Rake Task Variables
There are a bunch of variables you can supply to rake to modify the run.
MT_LIB_EXTRAS :: Extra libs to dynamically override/inject for custom runs.
N :: -n: Tests to run (string or /regexp/).
X :: -x: Tests to exclude (string or /regexp/).
A :: Any extra arguments. Honors shell quoting.
MT_CPU :: How many threads to use for parallel test runs
SEED :: -s --seed Sets random seed.
TESTOPTS :: Deprecated, same as A
FILTER :: Deprecated, same as A
== Writing Extensions
To define a plugin, add a file named minitest/XXX_plugin.rb to your project/gem. That file must be discoverable via ruby's LOAD_PATH (via rubygems or otherwise). Minitest will find and require that file using Gem.find_files. It will then try to call +plugin_XXX_init+ during startup. The option processor will also try to call +plugin_XXX_options+ passing the OptionParser instance and the current options hash. This lets you register your own command-line options. Here's a totally bogus example:
# minitest/bogus_plugin.rb:
module Minitest
def self.plugin_bogus_options(opts, options)
opts.on "--myci", "Report results to my CI" do
options[:myci] = true
options[:myci_addr] = get_myci_addr
options[:myci_port] = get_myci_port
end
end
def self.plugin_bogus_init(options)
self.reporter << MyCI.new(options) if options[:myci]
end
end
=== Adding custom reporters
Minitest uses composite reporter to output test results using multiple reporter instances. You can add new reporters to the composite during the init_plugins phase. As we saw in +plugin_bogus_init+ above, you simply add your reporter instance to the composite via <tt><<</tt>.
+AbstractReporter+ defines the API for reporters. You may subclass it and override any method you want to achieve your desired behavior.
start :: Called when the run has started. record :: Called for each result, passed or otherwise. report :: Called at the end of the run. passed? :: Called to see if you detected any problems.
Using our example above, here is how we might implement MyCI:
# minitest/bogus_plugin.rb
module Minitest
class MyCI < AbstractReporter
attr_accessor :results, :addr, :port
def initialize options
self.results = []
self.addr = options[:myci_addr]
self.port = options[:myci_port]
end
def record result
self.
