1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
|
= minitest-hooks
minitest-hooks adds around and before_all/after_all/around_all hooks for Minitest.
This allows you do things like run each suite of specs inside a database transaction,
running each spec inside its own savepoint inside that transaction, which can
significantly speed up testing for specs that share expensive database setup code.
= Installation
gem install minitest-hooks
= Source Code
Source code is available on GitHub at https://github.com/jeremyevans/minitest-hooks
= Usage
== In Specs (Minitest::Spec)
=== For all specs
require 'minitest/hooks/default'
=== For some specs
First, you need to require the library.
require 'minitest/hooks'
You can set the default for some specs to be <tt>Minitest::HooksSpec</tt>:
Minitest::Spec.register_spec_type(/something/, Minitest::HooksSpec)
Alternatively, you can include <tt>Minitest::Hooks</tt> in a specific spec class:
describe 'something' do
include Minitest::Hooks
end
=== before_all Hooks
To run code before any specs in the suite are executed, pass +:all+ to +before+:
describe 'something' do
before(:all) do
DB[:table].insert(:column=>1)
end
end
=== after_all Hooks
To run code after all specs in the suite are executed, pass +:all+ to +after+:
describe 'something' do
after(:all) do
DB[:table].delete
end
end
=== around Hooks
To run code around each spec in a suite, call +around+ with a block, and have the block
call +super+:
describe 'something' do
around do |&block|
DB.transaction(:rollback=>:always, :savepoint=>true, :auto_savepoint=>true) do
super(&block)
end
end
end
=== around_all Hooks
To run code around all specs in a suite, call <tt>around(:all)</tt> with a block,
and have the block call +super+:
describe 'something' do
around(:all) do |&block|
DB.transaction(:rollback=>:always) do
super(&block)
end
end
end
=== In Tests (Minitest::Test)
Create a subclass of <tt>Minitest::Test</tt> and include <tt>Minitest::Hooks</tt>,
and have your test classes subclass from that subclass:
require 'minitest/hooks/test'
class MyTest < Minitest::Test
include Minitest::Hooks
end
class TestSuite1 < MyTest
end
You can just define the +before_all+, +after_all+, +around+, and +around_all+ methods,
instead of using the spec DSL. Make sure to call super when overriding the methods.
class TestSuite1 < MyTest
def before_all
super
DB[:table].insert(:column=>1)
end
def after_all
DB[:table].delete
super
end
def around
DB.transaction(:rollback=>:always, :savepoint=>true, :auto_savepoint=>true) do
super
end
end
def around_all
DB.transaction(:rollback=>:always) do
super
end
end
end
= Behavior
== Hooks Just Define Methods
Just like the before/after hooks supported by minitest, all hooks supported by minitest-hooks
just define methods on the spec class, there is no magic ("It's just ruby"). This has a
couple of effects:
1. You cannot define multiple hooks of the same type in the same class. This is because
you cannot have multiple methods with the same name in the same class. If you define
a second hook of the same type in the same class, it will overwrite the previous hook,
just like ruby's behavior if you define a method twice in the same class.
2. For around and around(:all) hooks, you should always call super. If you want a subclass
around hook to run inside a superclass around hook, you need to call super in the
subclass hook and run the code inside the block you pass to super, then call block.call
somewhere inside the super block:
describe "superclass" do
around do |&block|
some_outer_method do
super(&block)
end
end
describe "subclass" do
around do |&block|
super do
some_inner_method do
block.call
end
end
end
end
end
You do not need to call super for before(:all) or after(:all) hooks. Both before(:all) and
after(:all) implicitly call super for you in the method they define, mirroring minitest's
behavior for before and after hooks.
3. All hooks share state/instance variables. So any instance variables you set in before(:all),
around(:all), or around are shared with the examples. Note that after(:all) will only see
instance variables set in before(:all) or around(:all), it will not see instance variables
set inside examples.
== All Spec Classes are Independent
The way minitest works, all spec classes are indepedent of other spec classes in terms
of how and when they are executed, even spec classes that are subclasses of other spec
classes. This means that for every spec class, the before(:all), after(:all), and
around(:all) hooks for that class will be executed, even if they were defined in the
spec's superclass and not in the spec class itself.
So if you have a spec superclass that uses before(:all), and a spec subclass for that
superclass, the before(:all) in the spec superclass will be run twice, once in the context
of an instance of the superclass, before executing the superclass's specs, and once in the
context of an instance of the subclass, before executing the subclass's specs.
== Order of Operations
For each spec class, the around(:all) hooks are run first. Both before(:all) and after(:all)
run inside around(:all). For each spec inside the spec the spec class, around will be called,
and before and after for each spec will be run inside around.
= License
MIT
= Author
Jeremy Evans <code@jeremyevans.net>
|