Class: Scope::TestCase
- Inherits:
-
MiniTest::Unit::TestCase
- Object
- MiniTest::Unit::TestCase
- Scope::TestCase
- Defined in:
- lib/scope.rb
Overview
A test case class which provides nested contexts. Subclasses will have the “setup”, “teardown”, and “should” methods available as class methods.
Class Method Summary collapse
- .context(name, &block) ⇒ Object
-
.context_for_test ⇒ Object
A map of test name => Context.
-
.focus ⇒ Object
“Focuses” the next test or context that’s defined after this method is called, ensuring that only that test/context is run.
- .inherited(subclass) ⇒ Object
- .setup(&block) ⇒ Object
-
.setup_once(&block) ⇒ Object
setup_once blocks are run just once for a context, and not on a per-test basis.
- .should(name, &block) ⇒ Object
- .teardown(&block) ⇒ Object
- .teardown_once(&block) ⇒ Object
Instance Method Summary collapse
-
#run(test_runner) ⇒ Object
run() is called by the MiniTest framework.
Class Method Details
.context(name, &block) ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/scope.rb', line 34 def self.context(name, &block) context_focused = false if @focus_enabled && @focus_next_test_or_context @focus_next_test_or_context = false @inside_focused_context = true context_focused = true end parent = @contexts.last new_context = Context.new(name, parent) parent.tests_and_subcontexts << new_context @contexts << new_context block.call @contexts.pop @inside_focused_context = false if context_focused end |
.context_for_test ⇒ Object
A map of test name => Context.
8 |
# File 'lib/scope.rb', line 8 def self.context_for_test() @context_for_test end |
.focus ⇒ Object
“Focuses” the next test or context that’s defined after this method is called, ensuring that only that test/context is run.
75 76 77 78 79 80 81 82 83 |
# File 'lib/scope.rb', line 75 def self.focus # Since we're focusing only the next test/context, remove any tests which were already defined. context_for_test.values.uniq.each do |context| context.tests_and_subcontexts.reject! { |test| test.is_a?(String) } end @focus_enabled = true @focus_next_test_or_context = true @inside_focused_context = false end |
.inherited(subclass) ⇒ Object
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/scope.rb', line 10 def self.inherited(subclass) # Calling Unit::TestCase's inherited() method is important, as that's how it registers test suites. super subclass.instance_eval do # Pretend the whole test is wrapped in a context, so we can always code as if tests are in contexts. @contexts = [Context.new("")] @context_for_test = {} # The tests defined in this test case. MiniTest::Unit::TestCase sorts these methods randomly or # alphabetically. Let's run them in the order they were defined, as that's least surprising. def test_methods() tests = [] stack = [@contexts.first] until stack.empty? do item = stack.pop stack += item.tests_and_subcontexts.reverse if item.is_a?(Context) tests << item if item.is_a?(String) end tests end end end |
.setup(&block) ⇒ Object
65 |
# File 'lib/scope.rb', line 65 def self.setup(&block) @contexts.last.setup= block end |
.setup_once(&block) ⇒ Object
setup_once blocks are run just once for a context, and not on a per-test basis. They are useful for integration tests with costly setup.
70 |
# File 'lib/scope.rb', line 70 def self.setup_once(&block) @contexts.last.setup_once = block end |
.should(name, &block) ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/scope.rb', line 50 def self.should(name, &block) # When focus_enabled is true, we'll only be running the next should() block that gets defined. if @focus_enabled return unless @focus_next_test_or_context || @inside_focused_context @focus_next_test_or_context &&= false end context_name = @contexts[1..-1].map { |context| context.name }.join(" ") context_name += " " unless context_name.empty? test_method_name = "#{context_name}should #{name}" define_method test_method_name, block @contexts.last.tests_and_subcontexts << test_method_name @context_for_test[test_method_name] = @contexts.last end |
.teardown(&block) ⇒ Object
66 |
# File 'lib/scope.rb', line 66 def self.teardown(&block) @contexts.last.teardown = block end |
.teardown_once(&block) ⇒ Object
71 |
# File 'lib/scope.rb', line 71 def self.teardown_once(&block) @contexts.last.teardown_once = block end |
Instance Method Details
#run(test_runner) ⇒ Object
run() is called by the MiniTest framework. This TestCase class is instantiated once per test method defined, and then run() is called on each test case instance.
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/scope.rb', line 87 def run(test_runner) test_name = self.__name__ context = self.class.context_for_test[test_name] result = nil begin begin # Prevent super from calling the minitest setup after the Scope setup blocks have already run. The # motivation is that RR puts hooks into setup to reset stubs and mocks and this needs to happen # *before* the test setup occurs. self.setup old_setup = self.method(:setup) def self.setup; end # Unit::TestCase's implementation of run() invokes the test method with exception handling. context.run_setup_and_teardown(self, test_name) { result = super(test_runner) } ensure def self.setup; old_setup; end end rescue *MiniTest::Unit::TestCase::PASSTHROUGH_EXCEPTIONS raise rescue Exception => error result = test_runner.puke(self.class, self.__name__, error) end result end |