Back to Repositories

Testing Report Access Policy Implementation in thoughtbot/guides

This test suite demonstrates best practices for RSpec testing by comparing recommended and non-recommended approaches to testing a ReportPolicy class. It specifically focuses on avoiding the use of let blocks in favor of more explicit test setups, showcasing how to properly structure permission-based policy tests.

Test Coverage Overview

The test suite provides comprehensive coverage of the ReportPolicy’s allowed? method functionality.

Key areas tested include:
  • User access validation for permitted reports
  • Access denial for unauthorized reports
  • Permission boundary checks with different report IDs

Implementation Analysis

The implementation showcases two contrasting approaches to RSpec testing – one using let blocks and another using explicit helper methods. The recommended approach employs instance_double for better isolation and a dedicated build_policy helper method for clearer test setup.

Key patterns include:
  • Direct object construction over let dependencies
  • Explicit context descriptions
  • Clear test case isolation

Technical Details

Testing tools and setup:
  • RSpec as the testing framework
  • instance_double for mock objects
  • Custom helper methods for test setup
  • Boolean expectations with be_allowed matcher

Best Practices Demonstrated

The test suite exemplifies several RSpec testing best practices:
  • Avoiding let for clearer test setup and debugging
  • Using descriptive context blocks
  • Implementing helper methods for test object construction
  • Proper use of mock objects with instance_double
  • Clear separation of test scenarios

thoughtbot/guides

testing-rspec/avoid_let_spec.rb

            
# Not recommended
describe ReportPolicy do
  let(:report_id) { 2 }
  let(:report_policy) do
    ReportPolicy.new(
      User.new(report_ids: [1,2]),
      Report.new(id: report_id)
    )
  end

  describe "#allowed?" do
    subject { report_policy.allowed? }
    
    context "when user has access to report" do
      it { should be true }
    end

    context "when user does not have access to report" do
      let(:report_id) { 3 }
      
      it { should be false }
    end
  end
end

# Recommended
describe ReportPolicy do
  describe "#allowed?" do
    context "when user has access to report" do
      it "returns true" do
        policy = build_policy(report_id: 2, allowed_report_ids: [1, 2])

        expect(policy).to be_allowed
      end
    end

    context "when user does not have access to report" do
      it "returns false" do
        policy = build_policy(report_id: 3, allowed_report_ids: [1, 2])

        expect(policy).not_to be_allowed
      end
    end
  end

  def build_policy(report_id:, allowed_report_ids:)
    user = instance_double("User", report_ids: allowed_report_ids)
    report = instance_double("Report", id: report_id)

    ReportPolicy.new(user, report)
  end
end