Module: Fixtury::MinitestHooks

Defined in:
lib/fixtury/minitest_hooks.rb

Overview

MinitestHooks is a module designed to hook into a Minitest test case, and provide a way to load fixtures into the test case. It is designed to be prepended into the test case class, and will automatically load fixtures before the test case is setup, and rollback any changes after the test case is torn down.

The module also provides a way to define fixture dependencies, and will automatically load those dependencies before the test case is setup.

A Set object named fixtury_dependencies is made available on the test class. This allows you to load all Minitest runnables and analyze what fixtures are needed. This is very helpful in CI pipelines when you want to prepare all fixtures ahead of time to share between multiple processes.

The setup and teardown attempt to manage a transaction for each registered database connection if ActiveRecord::Base is present. If use_transaction_tests or use_transactional_fixtures are present, those settings will be respected. If neither are present, a transaction will be used.

Examples:

class MyTest < Minitest::Test
  prepend Fixtury::MinitestHooks

  fixtury "user"
  fixtury "post"

  def test_something
    user # => returns the `users` fixture
    user.do_some_mutation
    assert_equal 1, user.mutations.count
  end
end

# In the above example, the `users` and `posts` fixtures will be loaded
# before the test case is setup, and any changes will be rolled back
# after the test case is torn down.

# The `fixtury` method also accepts a `:as` option, which can be used to
# define a named accessor method for a fixture. This is useful when
# defining a single fixture, and you want to access it using a different
# name. If no `:as` option is provided, the fixture will be accessed
# using the last segment of the fixture's pathname.

class MyTest < Minitest::Test
  prepend Fixtury::MinitestHooks

  fixtury "/my/user_record", as: :user

end

Defined Under Namespace

Modules: ClassMethods

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(klass) ⇒ Object

Raises:

  • (ArgumentError)


63
64
65
# File 'lib/fixtury/minitest_hooks.rb', line 63

def self.included(klass)
  raise ArgumentError, "#{name} should be prepended, not included"
end

.prepended(klass) ⇒ Object



57
58
59
60
61
# File 'lib/fixtury/minitest_hooks.rb', line 57

def self.prepended(klass)
  klass.class_attribute :fixtury_dependencies
  klass.fixtury_dependencies = Set.new
  klass.extend ClassMethods
end

Instance Method Details

#after_teardownObject

Minitest after_teardown hook. This will rollback any changes made to the fixtures after the test.



119
120
121
122
# File 'lib/fixtury/minitest_hooks.rb', line 119

def after_teardown(...)
  super
  fixtury_teardown if fixtury_dependencies.any?
end

#before_setupObject

Minitest before_setup hook. This will load the fixtures before the test.



113
114
115
116
# File 'lib/fixtury/minitest_hooks.rb', line 113

def before_setup(...)
  fixtury_setup if fixtury_dependencies.any?
  super
end

#fixtury(search) ⇒ Object

Access a fixture via a search term. This will access the fixture from the Fixtury store. If the fixture was not declared as a dependency, an error will be raised.

Parameters:

  • search (String)

    The search term to use to find the fixture.

Returns:

  • (Object)

    The fixture.

Raises:



131
132
133
134
135
136
137
138
139
# File 'lib/fixtury/minitest_hooks.rb', line 131

def fixtury(search)
  dfn = Fixtury.schema.get!(search)

  unless fixtury_dependencies.include?(dfn.pathname)
    raise Errors::UnknownTestDependencyError, "Unrecognized fixtury dependency `#{dfn.pathname}` for #{self.class}"
  end

  Fixtury.store.get(dfn.pathname)
end

#fixtury_database_connectionsArray<ActiveRecord::ConnectionAdapters::AbstractAdapter>

Retrieve all database connections that are currently registered with a writing role.

Returns:

  • (Array<ActiveRecord::ConnectionAdapters::AbstractAdapter>)

    The list of database connections.



144
145
146
147
148
149
# File 'lib/fixtury/minitest_hooks.rb', line 144

def fixtury_database_connections
  return [] unless defined?(ActiveRecord::Base)

  pools = ActiveRecord::Base.connection_handler.connection_pool_list(:writing)
  pools.map { |pool| pool.respond_to?(:lease_connection) ? pool.lease_connection : pool.connection }
end

#fixtury_load_all_fixtures!void

This method returns an undefined value.

Load all fixture dependencies that have not previously been loaded into the store.



174
175
176
177
178
179
180
181
# File 'lib/fixtury/minitest_hooks.rb', line 174

def fixtury_load_all_fixtures!
  fixtury_dependencies.each do |name|
    next if Fixtury.store.loaded?(name)

    ::Fixtury.log("preloading #{name.inspect}", name: "test", level: ::Fixtury::LOG_LEVEL_INFO)
    fixtury(name)
  end
end

#fixtury_setupObject

Load all dependenct fixtures and begin a transaction for each database connection.



152
153
154
155
156
157
158
159
160
# File 'lib/fixtury/minitest_hooks.rb', line 152

def fixtury_setup
  Fixtury.store.clear_stale_references!
  fixtury_load_all_fixtures!
  return unless fixtury_use_transactions?

  fixtury_database_connections.each do |conn|
    conn.begin_transaction joinable: false
  end
end

#fixtury_teardownObject

Rollback any changes made to the fixtures



163
164
165
166
167
168
169
# File 'lib/fixtury/minitest_hooks.rb', line 163

def fixtury_teardown
  return unless fixtury_use_transactions?

  fixtury_database_connections.each do |conn|
    conn.rollback_transaction if conn.open_transactions.positive?
  end
end

#fixtury_use_transactions?Boolean

Adhere to common Rails test transaction settings.

Returns:

  • (Boolean)


184
185
186
187
188
189
# File 'lib/fixtury/minitest_hooks.rb', line 184

def fixtury_use_transactions?
  return use_transactional_tests if respond_to?(:use_transactional_tests)
  return use_transactional_fixtures if respond_to?(:use_transactional_fixtures)

  true
end