Skip to content
This repository has been archived by the owner on Jul 24, 2020. It is now read-only.

Commit

Permalink
Refactor EquipmentModels controller spec
Browse files Browse the repository at this point in the history
Resolves #1587
 - Adds Mocker classes
 - Adds shared controller examples for successful and failed requests
  • Loading branch information
Sydney Young committed Aug 8, 2016
1 parent e8ffd13 commit 419cfa2
Show file tree
Hide file tree
Showing 9 changed files with 448 additions and 359 deletions.
555 changes: 205 additions & 350 deletions spec/controllers/equipment_models_controller_spec.rb

Large diffs are not rendered by default.

25 changes: 16 additions & 9 deletions spec/support/controller_helpers.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
# some basic helpers to simulate devise controller methods in specs
# frozen_string_literal: true
require Rails.root.join('spec/support/mockers/user_mock.rb')

module ControllerHelpers
def current_user
user_session_info =
response.request.env['rack.session']['warden.user.user.key']
return unless user_session_info
user_id = user_session_info[0][0]
User.find(user_id)
def mock_user_sign_in(user = UserMock.new(traits: [:findable]))
pass_app_setup_check
allow(request.env['warden']).to receive(:authenticate!).and_return(user)
# necessary for permissions to work
allow(ApplicationController).to receive(:current_user).and_return(user)
allow(Ability).to receive(:new).and_return(Ability.new(user))
allow_any_instance_of(described_class).to \
receive(:current_user).and_return(user)
end

def user_signed_in?
!current_user.nil?
private

def pass_app_setup_check
allow(AppConfig).to receive(:first).and_return(true) unless AppConfig.first
allow(User).to receive(:count).and_return(1) unless User.first
end
end
21 changes: 21 additions & 0 deletions spec/support/mockers/category_mock.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true
require Rails.root.join('spec/support/mockers/mocker.rb')
require Rails.root.join('spec/support/mockers/equipment_model_mock.rb')

class CategoryMock < Mocker
def self.klass
Category
end

def self.klass_name
'Category'
end

private

def with_equipment_models(models: nil, count: 1)
models ||= Array.new(count) { EquipmentModelMock.new }
parent_has_many(mocked_children: models, parent_sym: :category,
child_sym: :equipment_models)
end
end
21 changes: 21 additions & 0 deletions spec/support/mockers/equipment_item_mock.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true
require Rails.root.join('spec/support/mockers/mocker.rb')
require Rails.root.join('spec/support/mockers/equipment_model_mock.rb')

class EquipmentItemMock < Mocker
def self.klass
EquipmentItem
end

def self.klass_name
'EquipmentItem'
end

private

def with_model(model: nil)
model ||= EquipmentModelMock.new
child_of_has_many(mocked_parent: model, parent_sym: :equipment_model,
child_sym: :equipment_items)
end
end
32 changes: 32 additions & 0 deletions spec/support/mockers/equipment_model_mock.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true
require Rails.root.join('spec/support/mockers/mocker.rb')
require Rails.root.join('spec/support/mockers/category_mock.rb')
require Rails.root.join('spec/support/mockers/equipment_item_mock.rb')

class EquipmentModelMock < Mocker
def self.klass
EquipmentModel
end

def self.klass_name
'EquipmentModel'
end

private

def with_item(item:)
with_items(items: [item])
end

def with_items(items: nil, count: 1)
items ||= Array.new(count) { EquipmentItemMock.new }
parent_has_many(mocked_children: items, parent_sym: :equipment_model,
child_sym: :equipment_items)
end

def with_category(cat: nil)
cat ||= CategoryMock.new
child_of_has_many(mocked_parent: cat, parent_sym: :category,
child_sym: :equipment_models)
end
end
103 changes: 103 additions & 0 deletions spec/support/mockers/mocker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# frozen_string_literal: true
require 'rspec/mocks/standalone'

# This class behaves as an extension of rspec-mocks' instance_spy.
# It is intended to be extended and used to make mocking models much simpler!
#
# To create a new subclass, the following methods must be overridden:
# - self.klass must return the class that the subclass is mocking
# - self.klass_name must return a string that matches the class being mocked
#
# Some examples using the EquipmentModelMock subclass:
# A mock that can be "found" with EquipmentModel#find:
# EquipmentModelMock.new(traits: [:findable])
# A mock with a set of attributes:
# EquipmentModelMock.new(name: 'Camera', late_fee: 3)
# A mock with attributes and method stubs:
# EquipmentModelMock.new(name: 'Camera', model_restriced: false)
# A findable mock with attributes:
# EquipmentModelMock.new(traits: [:findable], name: 'Camera')
#
# A trait can be any method that exists on the mocker superclass or child class.
# To create an EquipmentModel that belongs to an existing category, camera:
# EquipmentModelMock.new(traits: [[:with_category, cat: camera]])
#
# Use caution before adding methods -- any method defined here should be usable
# by all subclasses, with the exception of the association stub methods.

class Mocker < RSpec::Mocks::InstanceVerifyingDouble
include RSpec::Mocks

FIND_METHODS = [:find, :find_by_id].freeze

def initialize(traits: [], **attrs)
# from RSpec::Mocks::ExampleMethods
# combination of #declare_verifying_double and #declare_double
ref = ObjectReference.for(self.class.klass_name)
RSpec::Mocks.configuration.verifying_double_callbacks.each do |block|
block.call(ref)
end
attrs ||= {}
super(ref, attrs)
as_null_object
process_traits(traits)
end

def process_traits(traits)
traits.each { |t| send(*t) }
end

private

def klass
Object
end

def klass_name
'Object'
end

def spy
self
end

# lets us use rspec-mock syntax in mockers
def receive(method_name, &block)
Matchers::Receive.new(method_name, block)
end

def allow(target)
AllowanceTarget.new(target)
end

# Traits
def findable
id = FactoryGirl.generate(:unique_id)
allow(spy).to receive(:id).and_return(id)
FIND_METHODS.each do |method|
allow(self.class.klass).to receive(method)
allow(self.class.klass).to receive(method).with(id).and_return(spy)
allow(self.class.klass).to receive(method).with(id.to_s).and_return(spy)
end
end

# Generalized association stubs
def child_of_has_many(mocked_parent:, parent_sym:, child_sym:)
allow(spy).to receive(parent_sym).and_return(mocked_parent)
children = if mocked_parent.send(child_sym).is_a? Array
mocked_parent.send(child_sym) << spy
else
[spy]
end
allow(mocked_parent).to receive(child_sym).and_return(children)
end

def parent_has_many(mocked_children:, parent_sym:, child_sym:)
if mocked_children.is_a? Array
mocked_children.each do |child|
allow(child).to receive(parent_sym).and_return(spy)
end
end
allow(spy).to receive(child_sym).and_return(mocked_children)
end
end
19 changes: 19 additions & 0 deletions spec/support/mockers/reservation_mock.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true
require Rails.root.join('spec/support/mockers/mocker.rb')

class ReservationMock < Mocker
def self.klass
Reservation
end

def self.klass_name
'Reservation'
end

private

def for_user(user:)
child_of_has_many(mocked_parent: user, parent_sym: :reserver,
child_sym: :reservations)
end
end
18 changes: 18 additions & 0 deletions spec/support/mockers/user_mock.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true
require Rails.root.join('spec/support/mockers/mocker.rb')

class UserMock < Mocker
def initialize(role = :user, traits: [], **attrs)
attrs = FactoryGirl.attributes_for(role).merge attrs
traits = [:findable] if traits.empty?
super(traits: traits, **attrs)
end

def self.klass
User
end

def self.klass_name
'User'
end
end
13 changes: 13 additions & 0 deletions spec/support/shared_examples/controller_examples.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true
require 'spec_helper'

shared_examples_for 'successful request' do |template|
it { is_expected.to respond_with(:success) }
it { is_expected.to render_template(template) }
it { is_expected.not_to set_flash }
end

shared_examples_for 'redirected request' do
it { expect(response).to be_redirect }
it { is_expected.to set_flash }
end

0 comments on commit 419cfa2

Please sign in to comment.