module MiniSpec::ClassAPI
Public Instance Methods
same as ‘before` except it will run after matched tests. @note `after` hooks will run even on failed tests.
however it wont run if some exception arise inside test.
# File lib/minispec/api/class/after.rb, line 7 def after *matchers, &proc proc || raise(ArgumentError, 'block is missing') matchers.flatten! matchers = [:*] if matchers.empty? return if after?.find {|x| x[0] == matchers && x[1].source_location == proc.source_location} after?.push([matchers, proc]) end
# File lib/minispec/api/class/after.rb, line 15 def after? filter = nil hooks_filter(@after ||= [], filter) end
code to run once after all tests finished. this callback will run only once. for callbacks that runs after any test @see after
@note this callback will run even if there are failed tests.
# File lib/minispec/api/class/after.rb, line 35 def after_all &proc proc || raise(ArgumentError, 'block is missing') @after_all = proc end
# File lib/minispec/api/class/after.rb, line 41 def after_all? @after_all end
# File lib/minispec/api/class/helpers.rb, line 101 def alias_helper target, source proc, opts = helpers[source] proc || raise(ArgumentError, '%s helper does not exists' % source.inspect) helper(target, opts, &proc) end
a block to wrap each test evaluation
@example
describe SomeClass do around do |test| DB.connect test.run DB.disconnect end end
# File lib/minispec/api/class/around.rb, line 16 def around *matchers, &proc proc || raise(ArgumentError, 'block is missing') matchers.flatten! matchers = [:*] if matchers.empty? return if around?.find {|x| x[0] == matchers && x[1].source_location == proc.source_location} around?.push([matchers, proc]) end
# File lib/minispec/api/class/around.rb, line 24 def around? filter = nil hooks_filter(@around ||= [], filter) end
a block to wrap all tests evaluation
# File lib/minispec/api/class/around.rb, line 40 def around_all &proc proc || raise(ArgumentError, 'block is missing') @around_all = proc end
# File lib/minispec/api/class/around.rb, line 46 def around_all? @around_all end
run some code before any or matching tests. if called without arguments the hook will run before any test. if any arguments passed it will run only before matched tests. strings, symbols and regexps accepted as arguments. also :except option accepted.
@example callback to run before any test
describe SomeTest do before do # ... end end
@example callback to run only before :cart test
describe Specs do before :cart do # ... end testing :cart do # ... end end
@example callback to run before any test that match /cart/
describe Specs do before /cart/ do # ... end testing :cart do # ... end end
@example callback to run before any test that match /cart/ except :load_cart
describe Specs do before /cart/, except: :load_cart do # ... end end
@example callback to run before any test that match /shoes/
but ones that match /red/ describe Specs do before /shoes/, except: /red/ do # ... end end
# File lib/minispec/api/class/before.rb, line 61 def before *matchers, &proc proc || raise(ArgumentError, 'block is missing') matchers.flatten! matchers = [:*] if matchers.empty? return if before?.find {|x| x[0] == matchers && x[1].source_location == proc.source_location} before?.push([matchers, proc]) end
# File lib/minispec/api/class/before.rb, line 69 def before? filter = nil hooks_filter(@before ||= [], filter) end
code to run once at spec initialization, just before start running tests. this callback will run only once - at spec initialization. for callbacks that runs before any test @see before
# File lib/minispec/api/class/before.rb, line 87 def before_all &proc proc || raise(ArgumentError, 'block is missing') @before_all = proc end
# File lib/minispec/api/class/before.rb, line 93 def before_all? @before_all end
by default MiniSpec
will stop evaluating a test on first failed assertion. ‘continue_on_failures true` will make MiniSpec
continue evaluating regardless failures.
@example set globally
MiniSpec.setup do continue_on_failures true end
@example set per spec
describe SomeTest do continue_on_failures true # ... end
# File lib/minispec/api/class.rb, line 79 def continue_on_failures status @continue_on_failures = status end
# File lib/minispec/api/class.rb, line 82 def continue_on_failures? @continue_on_failures end
define custom assertion helpers.
@note helpers can be overridden by name, that’s it, if some spec inherits ‘:a_duck?` helper you can use `helper(:a_duck?) { … }` to override it.
@note tested object are passed to helper via first argument.
any arguments passed to helper are sent after tested object.
@note if a block used on left side,
it will be passed as last argument and the helper is responsible to call it. please note that block will be passed as usual argument rather than a block.
@note if you need the current context to be passed into helper
use `:with_context` option. when doing so, the context will come as last argument.
@example
describe SomeTest do helper :a_pizza? do |food| does(food) =~ /cheese/ does(food) =~ /olives/ end testing :foods do food = Cook.some_food(with: 'cheese', and: 'olives') is(food).a_pizza? #=> passed food = Cook.some_food(with: 'potatoes') is(food).a_pizza? #=> failed end end
@example any other arguments are sent after tested object
describe SomeTest do helper :a_pizza? do |food, ingredients| does(food) =~ /dough/ does(ingredients).include? 'cheese' does(ingredients).include? 'olives' end testing :foods do ingredients = ['cheese', 'olives'] food = Cook.some_food(ingredients) is(food).a_pizza? ingredients end end
@example given block passed as last argument
# block comes as a usual argument rather than a block helper :is_invalid do |attr, block| e = assert(&block).raise(FormulaValidationError) assert(e.attr) == attr end test 'validates name' do assert(:name).is_invalid do formula "name with spaces" do url "foo" version "1.0" end end end
@example using ‘with_context` option to get context as last argument
describe SomeTest do helper :a_pizza?, with_context: true do |subject, ingredients, context| # context is a Hash containing :left_method, left_object, :left_proc and :negation keys end testing :foods do is(:smth).a_pizza? ['some', 'ingredients'] # helper's context will look like: # {left_method: :is, left_object: :smth, left_proc: nil, negation: nil} is { smth }.a_pizza? ['some', 'ingredients'] # helper's context will look like: # {left_method: :is, left_object: nil, left_proc: 'the -> { smth } proc', negation: nil} end end
# File lib/minispec/api/class/helpers.rb, line 92 def helper helper, opts = {}, &proc proc || raise(ArgumentError, 'block is missing') helpers[helper] = [proc, opts] end
# File lib/minispec/api/class/helpers.rb, line 97 def helpers @helpers ||= {} end
# File lib/minispec/api/class.rb, line 95 def hooks_filter callbacks, filter return callbacks unless filter callbacks.map do |(matchers,proc)| MiniSpec::Utils.any_match?(filter, matchers) ? [filter, matchers, proc] : nil end.compact end
import ‘:after` and `:after_all` hooks from base
# File lib/minispec/api/class/after.rb, line 24 def import_after base import_instance_variable(:after_all, base) base.after?.each {|(m,p)| self.after(m, &p)} end
import ‘:around` and `:around_all` from base
# File lib/minispec/api/class/around.rb, line 33 def import_around base import_instance_variable(:around_all, base) base.around?.each {|(m,p)| self.around(m, &p)} end
import ‘:before` and `:before_all` hooks from base
# File lib/minispec/api/class/before.rb, line 78 def import_before base import_instance_variable(:before_all, base) base.before?.each {|(m,p)| self.before(m, &p)} end
# File lib/minispec/api/class.rb, line 86 def import_continue_on_failures base import_instance_variable(:continue_on_failures, base) end
# File lib/minispec/api/class/helpers.rb, line 107 def import_helpers base base.helpers.each_pair {|h,(p,o)| self.helper(h, o, &p)} end
# File lib/minispec/api/class.rb, line 102 def import_instance_variable var, base return unless base.instance_variable_defined?('@%s' % var) val = base.instance_variable_get('@%s' % var) val.is_a?(Proc) ? send(var, &val) : send(var, val) end
# File lib/minispec/api/class/tests.rb, line 22 def import_tests base return if base == Minispec base.tests.each_pair {|l,(v,p)| self.send(v, l, &p)} end
# File lib/minispec/api/class/let.rb, line 35 def import_vars base base.vars.each_pair {|v,p| self.let(v, &p)} end
@example
module CPUTests include Minispec # CPU related tests end module RAMTests include Minispec # RAM related tests end describe :MacBook do include CPUTests include RAMTests # will run CPU and RAM tests + any tests defined here end
# File lib/minispec/api/class.rb, line 24 def included base base.send(:include, Minispec) MiniSpec::IMPORTABLES.each do |importable| base.send('import_%s' % importable, self) end end
# File lib/minispec/api/class.rb, line 154 def indent; 0 end
@example
describe Math do let(:x) { 0.1 } let(:y) { 1.0 } test 'x vs y' do assert(x) < y end end
# File lib/minispec/api/class/let.rb, line 14 def let meth, &proc proc || raise(ArgumentError, 'block is missing') vars[meth] = proc define_method(meth) { @__ms__vars[meth] ||= self.instance_exec(&proc) } end
same as let
except it will compute the value on every run
# File lib/minispec/api/class/let.rb, line 21 def let! meth, &proc proc || raise(ArgumentError, 'block is missing') vars[meth] = proc define_method(meth, &proc) end
@example
module CPUTests include Minispec # CPU related tests end module RAMTests include Minispec # RAM related tests end describe :MacBook do include CPUTests include RAMTests # we do not need :around hook nor included variables reset :around, :vars # will run CPU and RAM tests + any tests defined here end
# File lib/minispec/api/class.rb, line 54 def reset *importables importables.each do |importable| MiniSpec::IMPORTABLES.include?(inheritable.to_sym) || raise(ArgumentError, 'Do not know how to reset %s. Use one of %s' % [inheritable.inspect, MiniSpec::IMPORTABLES*', ']) self.send('reset_%s' % inheritable) end end
# File lib/minispec/api/class/after.rb, line 19 def reset_after @after = [] end
# File lib/minispec/api/class/after.rb, line 45 def reset_after_all remove_instance_variable(:@after_all) end
# File lib/minispec/api/class/around.rb, line 28 def reset_around @around = [] end
# File lib/minispec/api/class/around.rb, line 50 def reset_around_all remove_instance_variable(:@around_all) end
# File lib/minispec/api/class/before.rb, line 73 def reset_before @before = [] end
# File lib/minispec/api/class/before.rb, line 97 def reset_before_all remove_instance_variable(:@before_all) end
# File lib/minispec/api/class.rb, line 91 def reset_continue_on_failures remove_instance_variable(:@continue_on_failures) end
# File lib/minispec/api/class/helpers.rb, line 112 def reset_helpers @helpers = {} end
# File lib/minispec/api/class/tests.rb, line 28 def reset_tests @tests = {} end
# File lib/minispec/api/class/let.rb, line 40 def reset_vars @vars = {} end
# File lib/minispec/api/class.rb, line 156 def run reporter reporter.puts(spec_name, indent: indent) instance = self.allocate runner = proc do instance.__ms__boot tests.each_pair do |label,(verb,proc)| reporter.print('%s %s ' % [verb, label], indent: indent + 2) failures = instance.__ms__run_test(label) if skipped = instance.__ms__skipped? reporter.mark_as_skipped(spec_name, label, skipped) next end if failures.empty? reporter.mark_as_passed(spec_name, label) next end reporter.mark_as_failed(spec_fullname, label, verb, proc, failures) end instance.__ms__halt end if around_all = around_all? instance.instance_exec(runner, &around_all) else runner.call end reporter rescue Exception => e # catch exceptions raised inside :before_all/:after_all/:around_all hooks. # exceptions raised inside tests are caught by instance#__ms__run_test reporter.failed_specs << [spec_name, spec_proc, e] reporter end
# File lib/minispec/api/class.rb, line 151 def spec_name; self.name end
# File lib/minispec/api/class.rb, line 153 def spec_proc; nil end
# File lib/minispec/api/class/let.rb, line 27 def subject &proc let(:subject, &proc) end
# File lib/minispec/api/class/tests.rb, line 18 def tests @tests ||= {} end
# File lib/minispec/api/class/let.rb, line 31 def vars @vars ||= {} end