ruby_parameterized_testing
Parameterized testing utility for Ruby.
Installation
Add test dependency in your Gemfile.
group :test do
# For RSpec
gem "parameterized_testing-rspec", "~> 0.2"
# For minitest/spec
gem "parameterized_testing-minitest-spec", "~> 0.2"
end
Usage (with RSpec)
With this gem, parameterized tests can be written as follows:
# parameterized_testing-rspec example
RSpec.describe "something" do
# #parameterized is available in the context of RSpec ExampleGroup.
parameterized(:a, :b, :result) do
# Declare the concrete input corresponding to the parameters with #input.
input { [1, 2, 3] } # shorthand syntax
input { { a: 4, b: 5, result: 9 } } # verbose syntax
input("strings") { ["foo", "bar", "foobar"] } # input optionally takes a description
...
# Other than that, we can write tests in the same way as a conventional RSpec ExampleGroup.
subject { a + b }
it { is_expected.to eq result }
end
end
How #parameterized
works
It is important to notice that #parameterized
collects inputs by actually instance_exec
uting
the block in a dedicated context in order to embed the line number of input to #context
. In this context, all other method calls are ignored.
If you want to perform some extra procedure in the context of RSpec ExampleGroup, place them outside of #parameterized
.
Differences with rspec-parameterized
There is already a gem called rspec-parameterized
that supports parameterized testing.
parameterized_testing
does not depend on parser
, proc_to_ast
, or unparser
.
Code like the example above is conceptually1 expanded as follows:
RSpec.describe "something" do
sig_a_b_result = ::ParameterizedTesting::Signature.new(:a, :b, :result)
context 'input[0] at line 6' do
let(:_input_a_b_result) { sig_a_b_result.map([1, 2, 3]) }
let(:a) { __send__(:_input_a_b_result).fetch(:a) }
let(:b) { __send__(:_input_a_b_result).fetch(:b) }
let(:result) { __send__(:_input_a_b_result).fetch(:result) }
subject { a + b }
it { is_expected.to eq result }
end
context 'input[1] at line 7' do
let(:_input_a_b_result) { sig_a_b_result.map({ a: 4, b: 5, result: 9 }) }
...
end
context 'input[2] at line 8' do
let(:_input_a_b_result) { sig_a_b_result.map(["foo", "bar", "foobar"]) }
...
end
...
end
Since each input
is declared as a block, there are no helpers such as ref
or lazy
, which were in rspec-parameterized
.
Usage (with minitest/spec)
You can use the parameterization block in the same way as in the RSpec example.
describe "something" do
parameterized(:op, :result) do
input { [->(x, y) { x + y }, a + b] }
input { [->(x, y) { x * y }, a * b] }
subject { op.call(a, b) }
parameterized(:a, :b) do
input { [2, 3] }
input { [5, 7] }
it "tests something" do
_(subject).must_equal result
end
end
end
end
Development
$ git clone https://github.com/yubrot/ruby_parameterized_testing
$ cd gems/parameterized_testing
$ bin/setup
$ bundle exec rake --tasks
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/yubrot/ruby_parameterized_testing. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
License
The gem is available as open source under the terms of the MIT License.
Footnotes
-
The real implementation can be seen in driver.rb, for example. ↩