I had a chance to write tests for methods in concerns last week. This is the note about what I did.
First of all
I’m using rspec
and going to talk about rspec
Background
I have refactored Ruby on Rails models for the last few weeks. Then I made some concerns in our model layer to put common methods. I’ve written a lot of test codes in Ruby on Rails because I love test code. However, I’ve never written any for concerns before. So I was like “It’s a good opportunity to try.” Then I started to research how to do that.
What I did
I found a few articles about testing concerns like below
Then I realized I could categorize most of them into 2 types. The first one is creating a dummy object which includes concerns and testing the object. The other one is creating sharable behavior tests and testing the behavior with real objects. I can see points in both approaches. The first one is more about testing their concerns as isolating from others. The other is more focused on the behavior in a real context.
In terms of unit testing, I think the first approach makes more sense to me because I can focus on the concern’s specification more than the other. However, in my opinion, I don’t think it’s a good idea to create a dummy object only for testing because the dummy object could be far from a real use case and it could happen suddenly without anyone’s aware. At worst, the concern could work only in a test environment. So I decided to go with the second approach and try to stick with Rails way as much as possible.
I checked rails_helper.rb
and rspec_helper.rb
quickly and found what I could use in rails_helper.rb
# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
# run as spec files by default. This means that files in spec/support that end
# in _spec.rb will both be required and run as specs, causing the specs to be
# run twice. It is recommended that you do not name files matching this glob to
# end with _spec.rb. You can configure this pattern with the — pattern
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
#
# The following line is provided for convenience purposes. It has the downside
# of increasing the boot-up time by auto-requiring all files in the support
# directory. Alternatively, in the individual `*_spec.rb` files, manually
# require only the support files necessary.
#
Dir[Rails.root.join(‘spec’, ‘support’, ‘**’, ‘*.rb’)].sort.each { |f| require f }
After reading the section, I thought it could be a good idea to use the support directory to share the concern’s behavior tests.
I created spec/support/concerns/
directory and put shared examples in the file. Let’s say we have hashidable
concern. Then I create pec/support/concerns/hashidable_spec.rb
so that Ruby on Rails treats the file as spec files and I can use the shared examples everywhere. The following code is just an example.
require 'spec_helper'
shared_examples_for 'hashidable' do
let(:model) { create(described_class.to_s.underscore) }
describe '#encoded_id' do
subject { model.encoded_id }
it { is_expected.to eq('hogehoge') }
end
end
Then I execute it in the model tests which include the concern. Let’s say the model is User
require 'rails_helper'
describe Coach, type: :model do
it_behaves_like 'hashidable'
...other model specs here...
end
Then finally, I could test my concerns method in real contexts.
That’s it!