├── .ci.gemfile ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── CHANGELOG ├── Gemfile ├── MIT-LICENSE ├── README.rdoc ├── Rakefile ├── lib └── minitest │ ├── hooks.rb │ └── hooks │ ├── default.rb │ └── test.rb ├── minitest-hooks.gemspec └── spec ├── all.rb ├── errors └── example.rb ├── helper.rb ├── minitest_hooks_all_name_spec.rb ├── minitest_hooks_direct_spec.rb ├── minitest_hooks_errors_spec.rb ├── minitest_hooks_spec.rb ├── minitest_hooks_test.rb └── simplecov_helper.rb /.ci.gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | minitest_version = case RUBY_VERSION 4 | when /\A1.8/ 5 | '< 5.12' 6 | when /\A1.9/ 7 | '< 5.4' 8 | when /\A2.0/ 9 | '< 5.6' 10 | when /\A2.1/ 11 | '< 5.8' 12 | when /\A2.2/ 13 | '< 5.9' 14 | when /\A2.3/ 15 | '< 5.10' 16 | when /\A2.4/ 17 | '< 5.11' 18 | else 19 | '> 0' 20 | end 21 | gem 'minitest', minitest_version 22 | gem 'minitest-global_expectations', '>=1.0.1' 23 | 24 | if RUBY_VERSION >= '3.3' 25 | # Until minitest is updated to not require mutex_m 26 | gem 'mutex_m' 27 | end 28 | 29 | if RUBY_VERSION < '2.0' 30 | gem 'sequel', '< 5.70' 31 | else 32 | gem 'sequel' 33 | end 34 | 35 | if RUBY_VERSION < '2' 36 | gem 'rake', '<10.0.0' 37 | else 38 | gem 'rake' 39 | end 40 | 41 | if defined?(JRUBY_VERSION) 42 | gem 'jdbc-sqlite3' 43 | elsif RUBY_VERSION < '1.9.3' 44 | gem 'sqlite3', '<1.4' 45 | elsif RUBY_VERSION < '2.5' 46 | gem 'sqlite3', '< 1.5' 47 | else 48 | gem 'sqlite3' 49 | end 50 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | tests: 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | os: [ubuntu-latest] 18 | ruby: [ "2.0.0", 2.1, 2.3, 2.4, 2.5, 2.6, 2.7, "3.0", 3.1, 3.2, 3.3, 3.4, jruby-9.3, jruby-9.4, jruby-10.0 ] 19 | include: 20 | - { os: ubuntu-22.04, ruby: "1.9.3" } 21 | - { os: ubuntu-22.04, ruby: jruby-9.2 } 22 | runs-on: ${{ matrix.os }} 23 | name: ${{ matrix.ruby }} 24 | env: 25 | BUNDLE_GEMFILE: .ci.gemfile 26 | steps: 27 | - uses: actions/checkout@v4 28 | - run: sudo apt-get -yqq install libsqlite3-dev 29 | - uses: ruby/setup-ruby@v1 30 | with: 31 | ruby-version: ${{ matrix.ruby }} 32 | bundler-cache: true 33 | - run: bundle exec rake 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /rdoc 2 | /minitest-hooks-*.gem 3 | /Gemfile.lock 4 | /.bundle 5 | /coverage 6 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | === 1.5.2 (2024-08-14) 2 | 3 | * Fix use with minitest 5.25+ (paracycle) (#27, #28) 4 | 5 | === 1.5.1 (2023-07-27) 6 | 7 | * Do not include specs or Rakefile in the gem (jeremyevans) 8 | 9 | * Fix use with minitest 5.19+ by using Minitest instead of MiniTest as the constant (jeremyevans) 10 | 11 | === 1.5.0 (2018-05-21) 12 | 13 | * Fix use with minitest 5.11+ by using Minitest::Result in such cases (GUI) (#15) 14 | 15 | === 1.4.2 (2017-09-12) 16 | 17 | * Don't modify test instance name if before_all/after_all cause an error (jeremyevans) (#14) 18 | 19 | * Set around_all test instance name to strings so that exceptions in {before,after,around}_all don't break reporters (jeremyevans) (#14) 20 | 21 | * Set time to 0 for around_all test instance so that exceptions in {before,after,around}_all don't break reporters (jeremyevans) (#13, #14) 22 | 23 | === 1.4.1 (2017-07-31) 24 | 25 | * Set test/spec name correctly when running before(:all)/after(:all)/around(:all) hooks (rcrogers, jeremyevans) (#12) 26 | 27 | === 1.4.0 (2015-11-17) 28 | 29 | * Handle errors in before(:all)/after(:all)/around(:all) hooks (jeremyevans) 30 | 31 | === 1.3.0 (2015-08-17) 32 | 33 | * Don't run before_all/after_all/around_all hooks for classes with no tests/specs when using minitest >= 5.8.0 (jeremyevans) (#7) 34 | 35 | === 1.2.0 (2015-07-02) 36 | 37 | * Add minitest/hooks/test file, which doesn't require minitest/spec (janko-m) (#9, #10) 38 | 39 | === 1.1.0 (2015-05-11) 40 | 41 | * Remove unnecessary module inclusion (jeremyevans) 42 | 43 | * Add block-based around and around(:all) support (jeremyevans) 44 | 45 | === 1.0.1 (2015-04-26) 46 | 47 | * Fix homepage in gemspec (jeremyevans) 48 | 49 | === 1.0.0 (2015-04-26) 50 | 51 | * Initial Public Release 52 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2023 Jeremy Evans 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to 5 | deal in the Software without restriction, including without limitation the 6 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | sell copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | = minitest-hooks 2 | 3 | minitest-hooks adds around and before_all/after_all/around_all hooks for Minitest. 4 | This allows you do things like run each suite of specs inside a database transaction, 5 | running each spec inside its own savepoint inside that transaction, which can 6 | significantly speed up testing for specs that share expensive database setup code. 7 | 8 | = Installation 9 | 10 | gem install minitest-hooks 11 | 12 | = Source Code 13 | 14 | Source code is available on GitHub at https://github.com/jeremyevans/minitest-hooks 15 | 16 | = Usage 17 | 18 | == In Specs (Minitest::Spec) 19 | 20 | === For all specs 21 | 22 | require 'minitest/hooks/default' 23 | 24 | === For some specs 25 | 26 | First, you need to require the library. 27 | 28 | require 'minitest/hooks' 29 | 30 | You can set the default for some specs to be Minitest::HooksSpec: 31 | 32 | Minitest::Spec.register_spec_type(/something/, Minitest::HooksSpec) 33 | 34 | Alternatively, you can include Minitest::Hooks in a specific spec class: 35 | 36 | describe 'something' do 37 | include Minitest::Hooks 38 | end 39 | 40 | === before_all Hooks 41 | 42 | To run code before any specs in the suite are executed, pass +:all+ to +before+: 43 | 44 | describe 'something' do 45 | before(:all) do 46 | DB[:table].insert(:column=>1) 47 | end 48 | end 49 | 50 | === after_all Hooks 51 | 52 | To run code after all specs in the suite are executed, pass +:all+ to +after+: 53 | 54 | describe 'something' do 55 | after(:all) do 56 | DB[:table].delete 57 | end 58 | end 59 | 60 | === around Hooks 61 | 62 | To run code around each spec in a suite, call +around+ with a block, and have the block 63 | call +super+: 64 | 65 | describe 'something' do 66 | around do |&block| 67 | DB.transaction(:rollback=>:always, :savepoint=>true, :auto_savepoint=>true) do 68 | super(&block) 69 | end 70 | end 71 | end 72 | 73 | === around_all Hooks 74 | 75 | To run code around all specs in a suite, call around(:all) with a block, 76 | and have the block call +super+: 77 | 78 | describe 'something' do 79 | around(:all) do |&block| 80 | DB.transaction(:rollback=>:always) do 81 | super(&block) 82 | end 83 | end 84 | end 85 | 86 | === In Tests (Minitest::Test) 87 | 88 | Create a subclass of Minitest::Test and include Minitest::Hooks, 89 | and have your test classes subclass from that subclass: 90 | 91 | require 'minitest/hooks/test' 92 | class MyTest < Minitest::Test 93 | include Minitest::Hooks 94 | end 95 | 96 | class TestSuite1 < MyTest 97 | end 98 | 99 | You can just define the +before_all+, +after_all+, +around+, and +around_all+ methods, 100 | instead of using the spec DSL. Make sure to call super when overriding the methods. 101 | 102 | class TestSuite1 < MyTest 103 | def before_all 104 | super 105 | DB[:table].insert(:column=>1) 106 | end 107 | 108 | def after_all 109 | DB[:table].delete 110 | super 111 | end 112 | 113 | def around 114 | DB.transaction(:rollback=>:always, :savepoint=>true, :auto_savepoint=>true) do 115 | super 116 | end 117 | end 118 | 119 | def around_all 120 | DB.transaction(:rollback=>:always) do 121 | super 122 | end 123 | end 124 | end 125 | 126 | = Behavior 127 | 128 | == Hooks Just Define Methods 129 | 130 | Just like the before/after hooks supported by minitest, all hooks supported by minitest-hooks 131 | just define methods on the spec class, there is no magic ("It's just ruby"). This has a 132 | couple of effects: 133 | 134 | 1. You cannot define multiple hooks of the same type in the same class. This is because 135 | you cannot have multiple methods with the same name in the same class. If you define 136 | a second hook of the same type in the same class, it will overwrite the previous hook, 137 | just like ruby's behavior if you define a method twice in the same class. 138 | 139 | 2. For around and around(:all) hooks, you should always call super. If you want a subclass 140 | around hook to run inside a superclass around hook, you need to call super in the 141 | subclass hook and run the code inside the block you pass to super, then call block.call 142 | somewhere inside the super block: 143 | 144 | describe "superclass" do 145 | around do |&block| 146 | some_outer_method do 147 | super(&block) 148 | end 149 | end 150 | 151 | describe "subclass" do 152 | around do |&block| 153 | super do 154 | some_inner_method do 155 | block.call 156 | end 157 | end 158 | end 159 | end 160 | end 161 | 162 | You do not need to call super for before(:all) or after(:all) hooks. Both before(:all) and 163 | after(:all) implicitly call super for you in the method they define, mirroring minitest's 164 | behavior for before and after hooks. 165 | 166 | 3. All hooks share state/instance variables. So any instance variables you set in before(:all), 167 | around(:all), or around are shared with the examples. Note that after(:all) will only see 168 | instance variables set in before(:all) or around(:all), it will not see instance variables 169 | set inside examples. 170 | 171 | == All Spec Classes are Independent 172 | 173 | The way minitest works, all spec classes are indepedent of other spec classes in terms 174 | of how and when they are executed, even spec classes that are subclasses of other spec 175 | classes. This means that for every spec class, the before(:all), after(:all), and 176 | around(:all) hooks for that class will be executed, even if they were defined in the 177 | spec's superclass and not in the spec class itself. 178 | 179 | So if you have a spec superclass that uses before(:all), and a spec subclass for that 180 | superclass, the before(:all) in the spec superclass will be run twice, once in the context 181 | of an instance of the superclass, before executing the superclass's specs, and once in the 182 | context of an instance of the subclass, before executing the subclass's specs. 183 | 184 | == Order of Operations 185 | 186 | For each spec class, the around(:all) hooks are run first. Both before(:all) and after(:all) 187 | run inside around(:all). For each spec inside the spec class, around will be called, 188 | and before and after for each spec will be run inside around. 189 | 190 | = License 191 | 192 | MIT 193 | 194 | = Author 195 | 196 | Jeremy Evans 197 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "rake" 2 | require "rake/clean" 3 | 4 | CLEAN.include ["minitest-hooks-*.gem", "rdoc", "coverage"] 5 | 6 | desc "Build minitest-hooks gem" 7 | task :package=>[:clean] do |p| 8 | sh %{#{FileUtils::RUBY} -S gem build minitest-hooks.gemspec} 9 | end 10 | 11 | ### Specs 12 | 13 | desc "Run specs" 14 | task :spec do 15 | sh %{#{FileUtils::RUBY} #{"-w" if RUBY_VERSION >= '3'} #{'-W:strict_unused_block' if RUBY_VERSION >= '3.4'} spec/all.rb} 16 | end 17 | 18 | desc "Run specs with coverage" 19 | task :spec_cov do 20 | ENV['COVERAGE'] = '1' 21 | sh %{#{FileUtils::RUBY} spec/all.rb} 22 | end 23 | 24 | task :default=>:spec 25 | 26 | ### RDoc 27 | 28 | desc "Generate rdoc" 29 | task :rdoc do 30 | rdoc_dir = "rdoc" 31 | rdoc_opts = ["--line-numbers", "--inline-source", '--title', 'minitest-hooks: around and before_all/after_all/around_all hooks for Minitest'] 32 | 33 | begin 34 | gem 'hanna' 35 | rdoc_opts.concat(['-f', 'hanna']) 36 | rescue Gem::LoadError 37 | end 38 | 39 | rdoc_opts.concat(['--main', 'README.rdoc', "-o", rdoc_dir] + 40 | %w"README.rdoc CHANGELOG MIT-LICENSE" + 41 | Dir["lib/**/*.rb"] 42 | ) 43 | 44 | FileUtils.rm_rf(rdoc_dir) 45 | 46 | require "rdoc" 47 | RDoc::RDoc.new.document(rdoc_opts) 48 | end 49 | -------------------------------------------------------------------------------- /lib/minitest/hooks.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/hooks/test' 2 | require 'minitest/spec' 3 | 4 | # Spec subclass that includes the hook methods. 5 | class Minitest::HooksSpec < Minitest::Spec 6 | include Minitest::Hooks 7 | end 8 | -------------------------------------------------------------------------------- /lib/minitest/hooks/default.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/hooks' 2 | 3 | Minitest::Spec.register_spec_type(//, Minitest::HooksSpec) 4 | -------------------------------------------------------------------------------- /lib/minitest/hooks/test.rb: -------------------------------------------------------------------------------- 1 | require 'minitest' 2 | 3 | # Add support for around and before_all/after_all/around_all hooks to 4 | # minitest spec classes. 5 | module Minitest::Hooks 6 | # Add the class methods to the class. Also, include an additional 7 | # module in the class that before(:all) and after(:all) methods 8 | # work on a class that directly includes this module. 9 | def self.included(mod) 10 | super 11 | mod.instance_exec do 12 | extend(Minitest::Hooks::ClassMethods) 13 | end 14 | end 15 | 16 | # Empty method, necessary so that super calls in spec subclasses work. 17 | def before_all 18 | end 19 | 20 | # Empty method, necessary so that super calls in spec subclasses work. 21 | def after_all 22 | end 23 | 24 | # Method that just yields, so that super calls in spec subclasses work. 25 | def around_all 26 | yield 27 | end 28 | 29 | # Method that just yields, so that super calls in spec subclasses work. 30 | def around 31 | yield 32 | end 33 | 34 | # Run around hook inside, since time_it is run around every spec. 35 | def time_it 36 | super do 37 | around do 38 | yield 39 | end 40 | end 41 | end 42 | end 43 | 44 | module Minitest::Hooks::ClassMethods 45 | # Object used to get an empty new instance, as new by default will return 46 | # a dup of the singleton instance. 47 | NEW = Object.new.freeze 48 | 49 | # Unless name is NEW, return a dup singleton instance. 50 | def new(name) 51 | if name.equal?(NEW) 52 | return super('around_all') 53 | end 54 | 55 | instance = @instance.dup 56 | instance.name = name 57 | instance.failures = [] 58 | instance 59 | end 60 | 61 | # When running the specs in the class, first create a singleton instance, the singleton is 62 | # used to implement around_all/before_all/after_all hooks, and each spec will run as a 63 | # dup of the singleton instance. 64 | def with_info_handler(*args, &block) 65 | @instance = new(NEW) 66 | @instance.time = 0 67 | @instance.name = "around_all" 68 | 69 | reporter = args[0] 70 | 71 | begin 72 | @instance.around_all do 73 | begin 74 | @instance.capture_exceptions do 75 | @instance.name = "before_all" 76 | @instance.before_all 77 | end 78 | 79 | if @instance.failure 80 | failed = true 81 | _record_minitest_hooks_error(reporter, @instance) 82 | else 83 | super 84 | end 85 | ensure 86 | @instance.capture_exceptions do 87 | @instance.name = "after_all" unless failed 88 | @instance.after_all 89 | end 90 | if @instance.failure && !failed 91 | failed = true 92 | _record_minitest_hooks_error(reporter, @instance) 93 | end 94 | @instance.name = "around_all" unless failed 95 | end 96 | end 97 | rescue => e 98 | @instance.capture_exceptions do 99 | raise e 100 | end 101 | _record_minitest_hooks_error(reporter, @instance) 102 | end 103 | end 104 | 105 | # If type is :all, set the around_all hook, otherwise set the around hook. 106 | def around(type=nil, &block) 107 | meth = type == :all ? :around_all : :around 108 | define_method(meth, &block) 109 | end 110 | 111 | # If type is :all, set the before_all hook instead of the before hook. 112 | def before(type=nil, &block) 113 | if type == :all 114 | define_method(:before_all) do 115 | super() 116 | instance_exec(&block) 117 | end 118 | nil 119 | else 120 | super 121 | end 122 | end 123 | 124 | # If type is :all, set the after_all hook instead of the after hook. 125 | def after(type=nil, &block) 126 | if type == :all 127 | define_method(:after_all) do 128 | instance_exec(&block) 129 | super() 130 | end 131 | nil 132 | else 133 | super 134 | end 135 | end 136 | 137 | private 138 | 139 | def _record_minitest_hooks_error(reporter, instance) 140 | # In Minitest 5.11+, use Minitest::Result for wrapping the object to send 141 | # to the reporter. 142 | if(defined?(Minitest::Result)) 143 | result = Minitest::Result.from(instance) 144 | # :nocov: 145 | else 146 | result = instance 147 | # :nocov: 148 | end 149 | reporter.record result 150 | end 151 | end 152 | -------------------------------------------------------------------------------- /minitest-hooks.gemspec: -------------------------------------------------------------------------------- 1 | Gem::Specification.new do |s| 2 | s.name = 'minitest-hooks' 3 | s.version = '1.5.2' 4 | s.platform = Gem::Platform::RUBY 5 | s.extra_rdoc_files = ["README.rdoc", "CHANGELOG", "MIT-LICENSE"] 6 | s.rdoc_options += ["--quiet", "--line-numbers", "--inline-source", '--title', 'minitest-hooks: around and before_all/after_all/around_all hooks for Minitest', '--main', 'README.rdoc'] 7 | s.license = "MIT" 8 | s.summary = "Around and before_all/after_all/around_all hooks for Minitest" 9 | s.author = "Jeremy Evans" 10 | s.email = "code@jeremyevans.net" 11 | s.homepage = "http://github.com/jeremyevans/minitest-hooks" 12 | s.files = %w(MIT-LICENSE CHANGELOG README.rdoc) + Dir["lib/**/*.rb"] 13 | s.description = <5.3" 21 | s.add_development_dependency "sequel", '>4' 22 | s.add_development_dependency "sqlite3" 23 | s.add_development_dependency "rake" 24 | s.add_development_dependency "minitest-global_expectations" 25 | end 26 | -------------------------------------------------------------------------------- /spec/all.rb: -------------------------------------------------------------------------------- 1 | require 'rbconfig' 2 | ENV['RUBY'] ||= ENV["RUBY"] || File.join(RbConfig::CONFIG["bindir"], RbConfig::CONFIG["ruby_install_name"] + RbConfig::CONFIG["EXEEXT"]).sub(/.*\s.*/m, '"\&"') 3 | ENV['RUBYLIB'] = "lib:#{ENV['RUBYLIB']}" 4 | Dir['./spec/*_{spec,test}.rb'].each{|f| require f} 5 | -------------------------------------------------------------------------------- /spec/errors/example.rb: -------------------------------------------------------------------------------- 1 | require './spec/helper' 2 | require 'minitest/hooks/default' 3 | 4 | error = ENV['MINITEST_HOOKS_ERRORS'] 5 | 6 | module Minitest 7 | def self.plugin_result_inspector_reporter_init(options) 8 | self.reporter << ResultInspectorReporter.new(options[:io], options) 9 | end 10 | 11 | class ResultInspectorReporter < SummaryReporter 12 | def report 13 | results.each do |result| 14 | io.puts "result to_s: #{result.to_s.inspect}" 15 | # For Minitest 5.11+, we expect Minitest::Result objects. 16 | if defined?(Minitest::Result) 17 | io.puts "result source_location: #{result.source_location.inspect}" 18 | else 19 | # For older versions of Minitest, extract source_location in a 20 | # similar fashion to how some third party reporters expected to be 21 | # able to: 22 | # https://github.com/circleci/minitest-ci/blob/8b72b0f32f154d91b53d63d1d0a8a8fb3b01d726/lib/minitest/ci_plugin.rb#L139 23 | io.puts "result source_location: #{result.method(result.name).source_location.inspect}" 24 | end 25 | end 26 | end 27 | end 28 | end 29 | 30 | Minitest.extensions << "result_inspector_reporter" 31 | 32 | describe 'Minitest::Hooks error handling' do 33 | before(:all) do 34 | raise if error == 'before-all' 35 | end 36 | before do 37 | raise if error == 'before' 38 | end 39 | after do 40 | raise if error == 'after' 41 | end 42 | after(:all) do 43 | raise if error == 'after-all' 44 | end 45 | around do |&block| 46 | raise if error == 'around-before' 47 | super(&block) 48 | raise if error == 'around-after' 49 | end 50 | around(:all) do |&block| 51 | raise if error == 'around-all-before' 52 | super(&block) 53 | case error 54 | when 'before-all' 55 | name.must_equal 'before_all' 56 | when 'after-all' 57 | name.must_equal 'after_all' 58 | else 59 | name.must_equal 'around_all' 60 | end 61 | raise if error == 'around-all-after' 62 | end 63 | 64 | 3.times do |i| 65 | it "should work try #{i}" do 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /spec/helper.rb: -------------------------------------------------------------------------------- 1 | $:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "../lib/")) 2 | require 'rubygems' 3 | require 'sequel' 4 | 5 | if ENV.delete('COVERAGE') 6 | require_relative 'simplecov_helper' 7 | end 8 | 9 | ENV['MT_NO_PLUGINS'] = '1' # Work around stupid autoloading of plugins 10 | gem 'minitest' 11 | require 'minitest/global_expectations/autorun' 12 | DATABASE_URL = ENV['DATABASE_URL'] || (defined?(JRUBY_VERSION) ? 'jdbc:sqlite::memory:' : 'sqlite:/') 13 | -------------------------------------------------------------------------------- /spec/minitest_hooks_all_name_spec.rb: -------------------------------------------------------------------------------- 1 | require './spec/helper' 2 | require 'minitest/hooks/default' 3 | 4 | describe 'Minitest::Hooks error handling' do 5 | before(:all) do 6 | name.must_equal 'before_all' 7 | end 8 | after(:all) do 9 | name.must_equal 'after_all' 10 | end 11 | around(:all) do |&block| 12 | name.must_equal 'around_all' 13 | super(&block) 14 | name.must_equal 'around_all' 15 | end 16 | 17 | 3.times do |i| 18 | it "should work try #{i}" do 19 | end 20 | end 21 | end 22 | 23 | class MinitestHooksNameTest < Minitest::Test 24 | include Minitest::Hooks 25 | 26 | def before_all 27 | assert_equal 'before_all', name 28 | end 29 | def after_all 30 | assert_equal 'after_all', name 31 | end 32 | def around_all 33 | assert_equal 'around_all', name 34 | super 35 | assert_equal 'around_all', name 36 | end 37 | 38 | 3.times do |i| 39 | define_method "test_should_work_try_#{i}" do 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /spec/minitest_hooks_direct_spec.rb: -------------------------------------------------------------------------------- 1 | require './spec/helper' 2 | require 'minitest/hooks' 3 | 4 | NDB = Sequel.connect(DATABASE_URL) 5 | 6 | Minitest::Spec.register_spec_type(/no_default/, Minitest::Spec) 7 | 8 | describe 'Minitest::Hooks with transactions/savepoints no_default' do 9 | include Minitest::Hooks 10 | 11 | before(:all) do 12 | @ds_ba = @ds_aa 13 | @ds_ba.count.must_equal 1 + @i 14 | end 15 | before do 16 | @ds_be = @ds_ae 17 | @ds_be.count.must_equal 2 + @i * 2 18 | end 19 | after do 20 | @ds_be.count.must_equal 2 + @i * 2 21 | end 22 | after(:all) do 23 | @ds_ba.count.must_equal 1 + @i 24 | end 25 | around do |&block| 26 | @ds_aa.count.must_equal 1 + @i 27 | NDB.transaction(:rollback=>:always, :savepoint=>true, :auto_savepoint=>true) do 28 | @ds_ae = @ds_aa 29 | @ds_ae.insert(1) 30 | super(&block) 31 | end 32 | @ds_aa.count.must_equal 1 + @i 33 | end 34 | around(:all) do |&block| 35 | @i ||= 0 36 | NDB.transaction(:rollback=>:always) do 37 | NDB.create_table(:a){Integer :a} 38 | @ds_aa = NDB[:a] 39 | @ds_aa.count.must_equal 0 40 | @ds_aa.insert(1) 41 | super(&block) 42 | end 43 | NDB.table_exists?(:a).must_equal false 44 | end 45 | 46 | 3.times do |i| 47 | it "should work try #{i}" do 48 | @ds_aa.count.must_equal 2 49 | @ds_ae.count.must_equal 2 50 | @ds_ba.count.must_equal 2 51 | @ds_be.count.must_equal 2 52 | end 53 | end 54 | 55 | describe "in nested describe" do 56 | before(:all) do 57 | @ds_ba3 = @ds_ba 58 | @ds_ba2 = @ds_aa2 59 | @ds_ba2.count.must_equal 2 60 | end 61 | before do 62 | @ds_be3 = @ds_be 63 | @ds_be2 = @ds_ae2 64 | @ds_be2.count.must_equal 4 65 | end 66 | after do 67 | @ds_be2.count.must_equal 4 68 | end 69 | after(:all) do 70 | @ds_ba2.count.must_equal 2 71 | end 72 | around do |&block| 73 | @ds_aa.count.must_equal 2 74 | super() do 75 | @ds_aa.count.must_equal 3 76 | @ds_ae3 = @ds_ae 77 | @ds_ae2 = @ds_aa2 78 | @ds_ae2.insert(1) 79 | block.call 80 | @ds_aa.count.must_equal 4 81 | end 82 | @ds_aa.count.must_equal 2 83 | end 84 | around(:all) do |&block| 85 | @i ||= 1 86 | super() do 87 | @ds_aa.count.must_equal 1 88 | @ds_aa2 = @ds_aa 89 | @ds_aa2.insert(1) 90 | block.call 91 | @ds_aa.count.must_equal 2 92 | end 93 | NDB.table_exists?(:a).must_equal false 94 | end 95 | 96 | 3.times do |i| 97 | it "should work try #{i}" do 98 | @ds_aa.count.must_equal 4 99 | @ds_ae.count.must_equal 4 100 | @ds_ba.count.must_equal 4 101 | @ds_be.count.must_equal 4 102 | @ds_aa2.count.must_equal 4 103 | @ds_ae2.count.must_equal 4 104 | @ds_ba2.count.must_equal 4 105 | @ds_be2.count.must_equal 4 106 | @ds_ae3.count.must_equal 4 107 | @ds_ba3.count.must_equal 4 108 | @ds_be3.count.must_equal 4 109 | end 110 | end 111 | end 112 | end 113 | 114 | -------------------------------------------------------------------------------- /spec/minitest_hooks_errors_spec.rb: -------------------------------------------------------------------------------- 1 | require './spec/helper' 2 | require 'minitest/hooks/default' 3 | require 'open3' 4 | 5 | RUBY = ENV['RUBY'] || 'ruby' 6 | 7 | describe 'Minitest::Hooks error handling' do 8 | def self.run_test(desc, runs, errors) 9 | it "should handle errors in #{desc}" do 10 | ENV['MINITEST_HOOKS_ERRORS'] = desc 11 | Open3.popen3(RUBY, "spec/errors/example.rb", "-v") do |_, o, e, w| 12 | output = o.read 13 | output.must_match(/#{runs} runs, 0 assertions, 0 failures, #{errors} errors, 0 skips/) 14 | output.must_match(/result to_s: ".*?Minitest::Hooks error handling#\w+.*?spec\/errors\/example\.rb:\d+/) 15 | output.must_match(/result source_location: \["(unknown|.+?\.rb)", -?\d+/) 16 | output = e.read 17 | output.gsub!(/Picked up _JAVA_OPTIONS: [^\n]+\n/, '') 18 | output.must_equal '' 19 | w.value.exitstatus.wont_equal 0 if w 20 | end 21 | end 22 | end 23 | 24 | run_test "before-all", 1, 1 25 | run_test "before", 3, 3 26 | run_test "after", 3, 3 27 | run_test "after-all", 4, 1 28 | run_test "around-before", 1, 1 29 | run_test "around-after", 1, 1 30 | run_test "around-all-before", 1, 1 31 | run_test "around-all-after", 4, 1 32 | end 33 | -------------------------------------------------------------------------------- /spec/minitest_hooks_spec.rb: -------------------------------------------------------------------------------- 1 | require './spec/helper' 2 | require 'minitest/hooks/default' 3 | 4 | DB = Sequel.connect(DATABASE_URL) 5 | 6 | describe 'Minitest::Hooks with transactions/savepoints' do 7 | before(:all) do 8 | @ds_ba = @ds_aa 9 | @ds_ba.count.must_equal 1 + @i 10 | end 11 | before do 12 | @ds_be = @ds_ae 13 | @ds_be.count.must_equal 2 + @i * 2 14 | end 15 | after do 16 | @ds_be.count.must_equal 2 + @i * 2 17 | end 18 | after(:all) do 19 | @ds_ba.count.must_equal 1 + @i 20 | end 21 | around do |&block| 22 | @ds_aa.count.must_equal 1 + @i 23 | DB.transaction(:rollback=>:always, :savepoint=>true, :auto_savepoint=>true) do 24 | @ds_ae = @ds_aa 25 | @ds_ae.insert(1) 26 | super(&block) 27 | end 28 | @ds_aa.count.must_equal 1 + @i 29 | end 30 | around(:all) do |&block| 31 | @i ||= 0 32 | DB.transaction(:rollback=>:always) do 33 | DB.create_table(:a){Integer :a} 34 | @ds_aa = DB[:a] 35 | @ds_aa.count.must_equal 0 36 | @ds_aa.insert(1) 37 | super(&block) 38 | end 39 | DB.table_exists?(:a).must_equal false 40 | end 41 | 42 | 3.times do |i| 43 | it "should work try #{i}" do 44 | @ds_aa.count.must_equal 2 45 | @ds_ae.count.must_equal 2 46 | @ds_ba.count.must_equal 2 47 | @ds_be.count.must_equal 2 48 | end 49 | end 50 | 51 | describe "in nested describe" do 52 | before(:all) do 53 | @ds_ba3 = @ds_ba 54 | @ds_ba2 = @ds_aa2 55 | @ds_ba2.count.must_equal 2 56 | end 57 | before do 58 | @ds_be3 = @ds_be 59 | @ds_be2 = @ds_ae2 60 | @ds_be2.count.must_equal 4 61 | end 62 | after do 63 | @ds_be2.count.must_equal 4 64 | end 65 | after(:all) do 66 | @ds_ba2.count.must_equal 2 67 | end 68 | around do |&block| 69 | @ds_aa.count.must_equal 2 70 | super() do 71 | @ds_aa.count.must_equal 3 72 | @ds_ae3 = @ds_ae 73 | @ds_ae2 = @ds_aa2 74 | @ds_ae2.insert(1) 75 | block.call 76 | @ds_aa.count.must_equal 4 77 | end 78 | @ds_aa.count.must_equal 2 79 | end 80 | around(:all) do |&block| 81 | @i ||= 1 82 | super() do 83 | @ds_aa.count.must_equal 1 84 | @ds_aa2 = @ds_aa 85 | @ds_aa2.insert(1) 86 | block.call 87 | @ds_aa.count.must_equal 2 88 | end 89 | DB.table_exists?(:a).must_equal false 90 | end 91 | 92 | 3.times do |i| 93 | it "should work try #{i}" do 94 | @ds_aa.count.must_equal 4 95 | @ds_ae.count.must_equal 4 96 | @ds_ba.count.must_equal 4 97 | @ds_be.count.must_equal 4 98 | @ds_aa2.count.must_equal 4 99 | @ds_ae2.count.must_equal 4 100 | @ds_ba2.count.must_equal 4 101 | @ds_be2.count.must_equal 4 102 | @ds_ae3.count.must_equal 4 103 | @ds_ba3.count.must_equal 4 104 | @ds_be3.count.must_equal 4 105 | end 106 | end 107 | end 108 | end 109 | -------------------------------------------------------------------------------- /spec/minitest_hooks_test.rb: -------------------------------------------------------------------------------- 1 | require './spec/helper' 2 | require 'minitest/hooks/test' 3 | 4 | class MyTest < Minitest::Test 5 | include Minitest::Hooks 6 | end 7 | 8 | class TestMinitestHooks < MyTest 9 | DB = Sequel.connect(DATABASE_URL) 10 | 11 | def before_all 12 | super 13 | @ds_ba = @ds_aa 14 | assert_equal @ds_ba.count, 1 + @i 15 | end 16 | def setup 17 | super 18 | @ds_be = @ds_ae 19 | assert_equal @ds_be.count, 2 + @i * 2 20 | end 21 | def teardown 22 | assert_equal @ds_be.count, 2 + @i * 2 23 | super 24 | end 25 | def after_all 26 | assert_equal @ds_ba.count, 1 + @i 27 | super 28 | end 29 | def around 30 | assert_equal @ds_aa.count, 1 + @i 31 | DB.transaction(:rollback=>:always, :savepoint=>true, :auto_savepoint=>true) do 32 | @ds_ae = @ds_aa 33 | @ds_ae.insert(1) 34 | super 35 | end 36 | assert_equal @ds_aa.count, 1 + @i 37 | end 38 | def around_all 39 | @i ||= 0 40 | DB.transaction(:rollback=>:always) do 41 | DB.create_table(:a){Integer :a} 42 | @ds_aa = DB[:a] 43 | assert_equal @ds_aa.count, 0 44 | @ds_aa.insert(1) 45 | super 46 | end 47 | assert_equal DB.table_exists?(:a), false 48 | end 49 | 50 | 3.times do |i| 51 | define_method(:"test_should_work_#{i}") do 52 | assert_equal @ds_aa.count, 2 53 | assert_equal @ds_ae.count, 2 54 | assert_equal @ds_ba.count, 2 55 | assert_equal @ds_be.count, 2 56 | end 57 | end 58 | 59 | class TestMinitestHooks2 < self 60 | def before_all 61 | super 62 | @ds_ba3 = @ds_ba 63 | @ds_ba2 = @ds_aa2 64 | assert_equal @ds_ba2.count, 2 65 | end 66 | def setup 67 | super 68 | @ds_be3 = @ds_be 69 | @ds_be2 = @ds_ae2 70 | assert_equal @ds_be2.count, 4 71 | end 72 | def teardown 73 | assert_equal @ds_be2.count, 4 74 | super 75 | end 76 | def after_all 77 | assert_equal @ds_ba2.count, 2 78 | super 79 | end 80 | def around 81 | assert_equal @ds_aa.count, 2 82 | super do 83 | assert_equal @ds_aa.count, 3 84 | @ds_ae3 = @ds_ae 85 | @ds_ae2 = @ds_aa2 86 | @ds_ae2.insert(1) 87 | yield 88 | assert_equal @ds_aa.count, 4 89 | end 90 | assert_equal @ds_aa.count, 2 91 | end 92 | def around_all 93 | @i ||= 1 94 | super do 95 | assert_equal @ds_aa.count, 1 96 | @ds_aa2 = @ds_aa 97 | @ds_aa2.insert(1) 98 | yield 99 | assert_equal @ds_aa.count, 2 100 | end 101 | assert_equal DB.table_exists?(:a), false 102 | end 103 | 104 | 3.times do |i| 105 | define_method(:"test_should_work_#{i}") do 106 | assert_equal @ds_aa.count, 4 107 | assert_equal @ds_ae.count, 4 108 | assert_equal @ds_ba.count, 4 109 | assert_equal @ds_be.count, 4 110 | assert_equal @ds_aa2.count, 4 111 | assert_equal @ds_ae2.count, 4 112 | assert_equal @ds_ba2.count, 4 113 | assert_equal @ds_be2.count, 4 114 | assert_equal @ds_ae3.count, 4 115 | assert_equal @ds_ba3.count, 4 116 | assert_equal @ds_be3.count, 4 117 | end 118 | end 119 | end 120 | end 121 | -------------------------------------------------------------------------------- /spec/simplecov_helper.rb: -------------------------------------------------------------------------------- 1 | require 'simplecov' 2 | 3 | SimpleCov.instance_exec do 4 | enable_coverage :branch 5 | add_filter "/spec/" 6 | add_group('Missing'){|src| src.covered_percent < 100} 7 | add_group('Covered'){|src| src.covered_percent == 100} 8 | enable_for_subprocesses true 9 | 10 | at_fork do |pid| 11 | command_name "#{SimpleCov.command_name} (subprocess: #{pid})" 12 | self.print_error_status = false 13 | formatter SimpleCov::Formatter::SimpleFormatter 14 | minimum_coverage 0 15 | start 16 | end 17 | 18 | if ENV['COVERAGE'] == 'subprocess' 19 | ENV.delete('COVERAGE') 20 | command_name 'spawn' 21 | at_fork.call(Process.pid) 22 | else 23 | ENV['COVERAGE'] = 'subprocess' 24 | ENV['RUBYOPT'] = "#{ENV['RUBYOPT']} -r ./spec/simplecov_helper" 25 | start 26 | end 27 | end 28 | --------------------------------------------------------------------------------