our test suite $ rspec ....................................... … ....................................... Finished in 5 minutes 33.21 seconds 2818 examples, 0 failures, 8 pending That's an average of about 110ms per example!
< ActiveRecord::Base # ... # lots of other methods def can_apply_to?(job) application = application_for(job) return false if application and application.is_complete? job.applyable? and ( !client.uses_request_for_transfer? or !employee? or !employee.manager.nil? ) end def can_view_internal_jobs? employee? and client.uses_job_posting_types? end end
describe CandidateUser do let(:client) { Client.make! } let(:job) { Job.make!(client: client) } let(:cand) { CandidateUser.make!(client: client) } let(:application) { JobApplication.make!(job: job, candidate_user: cand) } describe "#can_apply_to?" do context "when the candidate has already applied" do it "should return false if application is complete" do application.update_attributes!(is_complete: true) cand.can_apply_to?(job).should be_false end end it "should return false if the job is not applyable" do # “Applyable”? What determines that? # etc. end end end
describe CandidateUser do let(:client) { Client.make! } let(:job) { Job.make!(client: client) } let(:cand) { CandidateUser.make!(client: client) } let(:application) { JobApplication.make!(job: job, candidate_user: cand) } describe "#can_apply_to?" do context "when the candidate has already applied" do it "should return false if application is complete" do application.update_attributes!(is_complete: true) cand.can_apply_to?(job).should be_false end end it "should return false if the job is not applyable" do # “Applyable”? What determines that? # etc. end end end
# When Spork loads... or every run if you're not using it require File.expand_path("../../config/environment", __FILE__) # aka: load all of rails please, kthxbye require 'rspec/rails' require 'shoulda/matchers/integrations/rspec' require 'rspec/autorun' require 'capybara/rspec' require 'capybara/poltergeist' require 'paperclip/matchers' # Each time the test suite is run require Rails.root.join("spec/support/blueprints.rb") Dir[Rails.root.join("spec/support/*.rb")].each { |f| require f } Dir[Rails.root.join("spec/shared_examples/*.rb")].each { |f| require f } That's a lot of dependencies!
class CandidateAbilities include Singleton attr_accessor :candidate def can_apply_to?(job) application = candidate.application_for(job) return false if application and application.is_complete? job.applyable? and ( !job.client.uses_request_for_transfer? or !candidate.employee? or !candidate.employee.manager.nil? ) end def can_view_internal_jobs? candidate.employee? and candidate.client.uses_job_posting_types? end end
< ActiveRecord::Base def abilities CandidateAbilities.instance.tap do |cp| cp.candidate = self end end delegate :can_apply_to?, :can_view_internal_jobs?, to: :abilities end if current_user.can_apply_to?(job) # ... end if current_user.can_view_internal_jobs? # ... end
describe CandidateAbilities do let(:candidate) { double("CandidateUser") } let(:client) { double("Client", uses_request_for_transfer?: false) } subject do CandidateAbilities.instance.tap do |cp| cp.candidate = candidate end end before { candidate.stub(:client).and_return(client) } describe "#can_view_internal_jobs?" do before do candidate.stub(:employee?) { true } candidate.client.stub(:uses_job_posting_types?) { true } end it "should return false if the user is not an employee" do candidate.stub(:employee?) { false } subject.can_view_internal_jobs?.should be_false end
con't it "should return false if the client does not use job posting types" do candidate.client.stub(:uses_job_posting_types?) { false } subject.can_view_internal_jobs?.should be_false end it "should return true otherwise" do subject.can_view_internal_jobs?.should be_true end end
do let(:candidate) { double("CandidateUser") } let(:client) { double("Client", uses_request_for_transfer?: false) } let(:job) { double("Job", client: client, applyable?: true) } subject do CandidateAbilities.instance.tap do |cp| cp.candidate = candidate end end before do candidate.stub(:client).and_return(client) candidate.stub(:application_for).with(job). and_return(double("JobApplication", is_complete?: false)) end describe "#can_apply_to?" do # ... end end
$ rspec spec/models/unit/ ................................................ Finished in 0.01754 seconds 48 examples, 0 failures About one-tenth of the time it takes to run one average example!
to a job Given I am a candidate And there is an open job When I view that job's details Then I should see an apply button Scenario: The job is not accepting applications Given I am a candidate And there is an inactive job When I view that job's details Then I should not see an apply button Scenario: Employee without a manager Given I am an employee And my company allows transfer requests And there is an open job But I do not have a manager When I view that job's details Then I should not see an apply button
Objects, the Unix Way - John Pignata http://blog.codeclimate.com/blog/2012/11/28/your-objects-the-unix-way Making Little Classes out of Big Ones – Avdi Grimm http://devblog.avdi.org/2012/05/25/making-little-classes-out-of-big-ones-video/ Fast Rails Tests – Corey Haines http://www.confreaks.com/videos/641 Refactoring from Good to Great – Ben Orenstein http://www.confreaks.com/videos/1233 Go Ahead, Make a Mess – Sandi Metz http://www.confreaks.com/videos/1253