Let’s say you have a new ActiveRecord concern to add a new feature to your models. This concern extracts a database behavior. For simplicity, we are going to use a database query for tagging:
module TaggableConcern
extend ActiveSupport :: Concern
included do
scope :with_tag , -> ( tag ) {
where ( '? = ANY(tags)' , tag )
}
scope :with_tags , -> ( tags ) {
where ( 'tags @> ARRAY[?]::varchar[]' , Array ( tags ))
}
end
end
How do you test concerns in isolation without including them in an application model?
PostgreSQL is packed full of wonderful features. One of those features is hidden in the CREATE TABLE synopsis:
CREATE TEMPORARY TABLE table_name (...)
ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP }
Using this in Rails is pretty straightforward because create_table accepts :temporary
as boolean argument to mark the table as ephemeral and options
parameter to add extra options for the table definition, like when to remove it:
create_table :my_table , temporary: true , options: 'ON COMMIT DROP' do | t |
...
end
Here is an example using this:
RSpec . describe TaggableConcern , type: :model do
before do
class TempBook < ApplicationRecord
include TaggableConcern
connection . create_table :temp_books , temporary: true , options: 'ON COMMIT DROP' do | t |
t . string :name
t . string :tags , array: true
t . timestamps
end
end
end
let! ( :ruby ) do
TempBook . create! (
name: 'Programming Rails' ,
tags: %w[ruby rails web]
)
end
let! ( :elixir ) do
TempBook . create! (
name: 'Programming Phoenix' ,
tags: %w[elixir phoenix web]
)
end
let! ( :go ) do
TempBook . create! (
name: 'Programming Go' ,
tags: %w[go programming]
)
end
describe '.with_tag' do
subject { TempBook . with_tag ( query ) }
context 'with nil value' do
let ( :query ) { nil }
it { is_expected . to be_empty }
end
context 'with one match' do
let ( :query ) { 'ruby' }
it { is_expected . to match_array ([ ruby ]) }
end
context 'with multiple matches' do
let ( :query ) { 'web' }
it { is_expected . to match_array ([ ruby , elixir ]) }
end
end
describe '.with_tags' do
subject { TempBook . with_tags ( query ) }
context 'with nil value' do
let ( :query ) { nil }
it { is_expected . to be_empty }
end
context 'with empty array' do
let ( :query ) { [] }
it { is_expected . to be_empty }
end
context 'with a common tag' do
let ( :query ) { 'web' }
it { is_expected . to match_array ([ ruby , elixir ]) }
end
context 'with a common tag as array' do
let ( :query ) { [ 'web' ] }
it { is_expected . to match_array ([ ruby , elixir ]) }
end
context 'with mixed tags' do
let ( :query ) { [ 'ruby' , 'elixir' ] }
it { is_expected . to be_empty }
end
context 'with mixed tags' do
let ( :query ) { [ 'ruby' , 'web' ] }
it { is_expected . to match_array ([ ruby ]) }
end
end
end
Finished in 0.1783 seconds (files took 0.59146 seconds to load)
9 examples, 0 failures