class RSpec::Core::ExampleGroup
{MemoizedHelpers} and {Pending}.
There are additional instance methods available to your examples defined in
defined in {Hooks}, {MemoizedHelpers::ClassMethods} and {SharedExampleGroup}.
Besides the class methods defined here, there are other interesting macros
to which they belong.
evalutaed in the context of an instance of the specific ExampleGroup subclass
in the context of a new subclass of ExampleGroup. Individual examples are
Example group bodies (e.g. ‘describe` or `context` blocks) are evaluated
is declared.
which serves as a wrapper for an instance of the ExampleGroup in which it
The object returned by `it “does something”` is an instance of Example,
The object returned by `describe Thing` is a subclass of ExampleGroup.
end
end
it “does something” do
describe Thing do
rspec-core. Consider this example:
ExampleGroup and {Example} are the main structural elements of
def self.all_apply?(filters)
- Private: -
def self.all_apply?(filters) MetadataFilter.all_apply?(filters, metadata) end
def self.any_apply?(filters)
- Private: -
def self.any_apply?(filters) MetadataFilter.any_apply?(filters, metadata) end
def self.before_context_ivars
- Private: -
def self.before_context_ivars @before_context_ivars ||= {} end
def self.children
- Private: -
def self.children @children ||= [] end
def self.declaration_line_numbers
- Private: -
def self.declaration_line_numbers @declaration_line_numbers ||= [metadata[:line_number]] + examples.collect {|e| e.metadata[:line_number]} + children.inject([]) {|l,c| l + c.declaration_line_numbers} end
def self.define_example_group_method(name, metadata={})
- See: DSL#describe -
Other tags:
- Yield: - The example group definition
Parameters:
-
metadata
(Hash
) -- Additional metadata to attach to the example group -
name
(String
) -- The example group doc string
Other tags:
- Private: -
def self.define_example_group_method(name, metadata={}) define_singleton_method(name) do |*args, &example_group_block| thread_data = RSpec.thread_local_metadata top_level = self == ExampleGroup if top_level if thread_data[:in_example_group] raise "Creating an isolated context from within a context is " + "not allowed. Change `RSpec.#{name}` to `#{name}` or " + "move this to a top-level scope." end thread_data[:in_example_group] = true end begin description = args.shift combined_metadata = metadata.dup combined_metadata.merge!(args.pop) if args.last.is_a? Hash args << combined_metadata subclass(self, description, args, &example_group_block).tap do |child| children << child end ensure thread_data.delete(:in_example_group) if top_level end end RSpec::Core::DSL.expose_example_group_alias(name) end
def self.define_example_method(name, extra_options={})
- Yield: - the example object
Parameters:
-
implementation
(Block
) -- -
extra_options
(Hash
) -- -
name
(String
) --
Other tags:
- Private: -
def self.define_example_method(name, extra_options={}) define_singleton_method(name) do |*all_args, &block| desc, *args = *all_args options = Metadata.build_hash_from(args) options.update(:skip => RSpec::Core::Pending::NOT_YET_IMPLEMENTED) unless block options.update(extra_options) # Metadata inheritance normally happens in `Example#initialize`, # but for `:pending` specifically we need it earlier. pending_metadata = options[:pending] || metadata[:pending] if pending_metadata options, block = ExampleGroup.pending_metadata_and_block_for( options.merge(:pending => pending_metadata), block ) end examples << RSpec::Core::Example.new(self, desc, options, block) examples.last end end
def self.define_nested_shared_group_method(new_name, report_label="it should behave like")
- See: SharedExampleGroup -
Other tags:
- Private: -
def self.define_nested_shared_group_method(new_name, report_label="it should behave like") define_singleton_method(new_name) do |name, *args, &customization_block| # Pass :caller so the :location metadata is set properly... # otherwise, it'll be set to the next line because that's # the block's source_location. group = example_group("#{report_label} #{name}", :caller => caller) do find_and_eval_shared("examples", name, *args, &customization_block) end group.metadata[:shared_group_name] = name group end end
def self.define_singleton_method(*a, &b)
- Private: -
def self.define_singleton_method(*a, &b) (class << self; self; end).__send__(:define_method, *a, &b) end
def self.delegate_to_metadata(*names)
- Private: -
def self.delegate_to_metadata(*names) names.each do |name| define_singleton_method(name) { metadata.fetch(name) } end end
def self.descendant_filtered_examples
- Private: -
def self.descendant_filtered_examples @descendant_filtered_examples ||= filtered_examples + children.inject([]){|l,c| l + c.descendant_filtered_examples} end
def self.descendants
- Private: -
def self.descendants @_descendants ||= [self] + children.inject([]) {|list, c| list + c.descendants} end
def self.description
-
(String)
- the current example group description
def self.description description = metadata[:description] RSpec.configuration.format_docstrings_block.call(description) end
def self.ensure_example_groups_are_configured
- Private: -
def self.ensure_example_groups_are_configured unless defined?(@@example_groups_configured) RSpec.configuration.configure_mock_framework RSpec.configuration.configure_expectation_framework @@example_groups_configured = true end end
def self.examples
- Private: -
def self.examples @examples ||= [] end
def self.fail_fast?
- Private: -
def self.fail_fast? RSpec.configuration.fail_fast? end
def self.filtered_examples
- Private: -
def self.filtered_examples RSpec.world.filtered_examples[self] end
def self.find_and_eval_shared(label, name, *args, &customization_block)
- Private: -
def self.find_and_eval_shared(label, name, *args, &customization_block) unless shared_block = RSpec.world.shared_example_group_registry.find(parent_groups, name) raise ArgumentError, "Could not find shared #{label} #{name.inspect}" end module_exec(*args, &shared_block) module_exec(&customization_block) if customization_block end
def self.for_filtered_examples(reporter, &block)
- Private: -
def self.for_filtered_examples(reporter, &block) filtered_examples.each(&block) children.each do |child| reporter.example_group_started(child) child.for_filtered_examples(reporter, &block) reporter.example_group_finished(child) end false end
def self.include_context(name, *args, &block)
- See: SharedExampleGroup -
def self.include_context(name, *args, &block) find_and_eval_shared("context", name, *args, &block) end
def self.include_examples(name, *args, &block)
- See: SharedExampleGroup -
def self.include_examples(name, *args, &block) find_and_eval_shared("examples", name, *args, &block) end
def self.metadata
- See: Metadata -
def self.metadata @metadata if defined?(@metadata) end
def self.ordering_strategy
- Private: -
def self.ordering_strategy order = metadata.fetch(:order, :global) registry = RSpec.configuration.ordering_registry registry.fetch(order) do warn <<-WARNING.gsub(/^ +\|/, '') |WARNING: Ignoring unknown ordering specified using `:order => #{order.inspect}` metadata. | Falling back to configured global ordering. | Unrecognized ordering specified at: #{location} WARNING registry.fetch(:global) end end
def self.parent_groups
def self.parent_groups @parent_groups ||= ancestors.select {|a| a < RSpec::Core::ExampleGroup} end
def self.pending_metadata_and_block_for(options, block)
- Private: -
def self.pending_metadata_and_block_for(options, block) if String === options[:pending] reason = options[:pending] else options[:pending] = true reason = RSpec::Core::Pending::NO_REASON_GIVEN end # Assign :caller so that the callback's source_location isn't used # as the example location. options[:caller] ||= Metadata.backtrace_from(block) # This will fail if no block is provided, which is effectively the # same as failing the example so it will be marked correctly as # pending. callback = Proc.new { pending(reason); instance_exec(&block) } return options, callback end
def self.run(reporter)
def self.run(reporter) if RSpec.world.wants_to_quit RSpec.world.clear_remaining_example_groups if top_level? return end reporter.example_group_started(self) begin run_before_context_hooks(new) result_for_this_group = run_examples(reporter) results_for_descendants = ordering_strategy.order(children).map { |child| child.run(reporter) }.all? result_for_this_group && results_for_descendants rescue Pending::SkipDeclaredInExample => ex for_filtered_examples(reporter) {|example| example.skip_with_exception(reporter, ex) } rescue Exception => ex RSpec.world.wants_to_quit = true if fail_fast? for_filtered_examples(reporter) {|example| example.fail_with_exception(reporter, ex) } ensure run_after_context_hooks(new) before_context_ivars.clear reporter.example_group_finished(self) end end
def self.run_after_context_hooks(example_group_instance)
- Private: -
def self.run_after_context_hooks(example_group_instance) return if descendant_filtered_examples.empty? set_ivars(example_group_instance, before_context_ivars) ContextHookMemoizedHash::After.isolate_for_context_hook(example_group_instance) do hooks.run(:after, :context, example_group_instance) end end
def self.run_before_context_hooks(example_group_instance)
- Private: -
def self.run_before_context_hooks(example_group_instance) return if descendant_filtered_examples.empty? begin set_ivars(example_group_instance, superclass.before_context_ivars) ContextHookMemoizedHash::Before.isolate_for_context_hook(example_group_instance) do hooks.run(:before, :context, example_group_instance) end ensure store_before_context_ivars(example_group_instance) end end
def self.run_examples(reporter)
- Private: -
def self.run_examples(reporter) ordering_strategy.order(filtered_examples).map do |example| next if RSpec.world.wants_to_quit instance = new set_ivars(instance, before_context_ivars) succeeded = example.run(instance, reporter) RSpec.world.wants_to_quit = true if fail_fast? && !succeeded succeeded end.all? end
def self.set_it_up(*args, &example_group_block)
- Private: -
def self.set_it_up(*args, &example_group_block) # Ruby 1.9 has a bug that can lead to infinite recursion and a # SystemStackError if you include a module in a superclass after # including it in a subclass: https://gist.github.com/845896 # To prevent this, we must include any modules in RSpec::Core::ExampleGroup # before users create example groups and have a chance to include # the same module in a subclass of RSpec::Core::ExampleGroup. # So we need to configure example groups here. ensure_example_groups_are_configured description = args.shift user_metadata = Metadata.build_hash_from(args) args.unshift(description) @metadata = Metadata::ExampleGroupHash.create( superclass_metadata, user_metadata, *args, &example_group_block ) hooks.register_globals(self, RSpec.configuration.hooks) RSpec.world.configure_group(self) end
def self.set_ivars(instance, ivars)
- Private: -
def self.set_ivars(instance, ivars) ivars.each {|name, value| instance.instance_variable_set(name, value)} end
def self.store_before_context_ivars(example_group_instance)
- Private: -
def self.store_before_context_ivars(example_group_instance) return if example_group_instance.instance_variables.empty? example_group_instance.instance_variables.each { |ivar| before_context_ivars[ivar] = example_group_instance.instance_variable_get(ivar) } end
def self.subclass(parent, description, args, &example_group_block)
- Private: -
def self.subclass(parent, description, args, &example_group_block) subclass = Class.new(parent) subclass.set_it_up(description, *args, &example_group_block) ExampleGroups.assign_const(subclass) subclass.module_exec(&example_group_block) if example_group_block # The LetDefinitions module must be included _after_ other modules # to ensure that it takes precedence when there are name collisions. # Thus, we delay including it until after the example group block # has been eval'd. MemoizedHelpers.define_helpers_on(subclass) subclass end
def self.superclass_metadata
-
(Metadata)
- belonging to the parent of a nested {ExampleGroup}
Other tags:
- Private: -
def self.superclass_metadata @superclass_metadata ||= self.superclass.respond_to?(:metadata) ? self.superclass.metadata : nil end
def self.top_level?
- Private: -
def self.top_level? @top_level ||= superclass == ExampleGroup end
def self.top_level_description
- Private: -
def self.top_level_description parent_groups.last.description end
def described_class
end
end
described_class == Thing
it "does something" do
describe Thing do
@example
Returns nil if the subject is not a class or module.
Returns the class or module passed to the `describe` method (or alias).
def described_class self.class.described_class end