module RSpec::Rails::Mocks
def mock_model(string_or_model_class, stubs = {})
* A String representing a Class that extends ActiveModel::Naming
* A String representing a Class that does not exist
`string_or_model_class` can be any of:
new_record?).
ActiveModel API (which declares persisted?, not
extension frameworks that have yet to update themselves to the
persisted?, and is present only for compatibility with
stubbed out implicitly. new_record? returns the inverse of
NOTE that only ActiveModel's methods, plus new_record?, are
impersonating models that don't exist yet.
stubbed (via add_stubs) if `stubs` is passed. This is most useful for
ActiveModel methods stubbed out. Additional methods may be easily
Creates a test double representing `string_or_model_class` with common
def mock_model(string_or_model_class, stubs = {}) RSpec.deprecate("`mock_model`", :replacement => "the `rspec-activemodel-mocks` gem") if String === string_or_model_class if Object.const_defined?(string_or_model_class) model_class = Object.const_get(string_or_model_class) else model_class = Object.const_set(string_or_model_class, Class.new do extend ::ActiveModel::Naming def self.primary_key; :id; end end) end else model_class = string_or_model_class end unless model_class.kind_of? ::ActiveModel::Naming raise ArgumentError.new <<-EOM ck_model method can only accept as its first argument: String representing a Class that does not exist String representing a Class that extends ActiveModel::Naming Class that extends ActiveModel::Naming eived #{model_class.inspect} end stubs = stubs.reverse_merge(:id => next_id) stubs = stubs.reverse_merge(:persisted? => !!stubs[:id], :destroyed? => false, :marked_for_destruction? => false, :valid? => true, :blank? => false) double("#{model_class.name}_#{stubs[:id]}", stubs).tap do |m| m.singleton_class.class_eval do include ActiveModelInstanceMethods include ActiveRecordInstanceMethods if defined?(ActiveRecord) include ::ActiveModel::Conversion include ::ActiveModel::Validations end if defined?(ActiveRecord) [:save, :update_attributes, :update].each do |key| if stubs[key] == false RSpec::Mocks.allow_message(m.errors, :empty?).and_return(false) end end end m.__send__(:__mock_proxy).instance_eval(<<-CODE, __FILE__, __LINE__) def @object.is_a?(other) #{model_class}.ancestors.include?(other) end unless #{stubs.has_key?(:is_a?)} def @object.kind_of?(other) #{model_class}.ancestors.include?(other) end unless #{stubs.has_key?(:kind_of?)} def @object.instance_of?(other) other == #{model_class} end unless #{stubs.has_key?(:instance_of?)} def @object.__model_class_has_column?(method_name) #{model_class}.respond_to?(:column_names) && #{model_class}.column_names.include?(method_name.to_s) end def @object.has_attribute?(attr_name) __model_class_has_column?(attr_name) end unless #{stubs.has_key?(:has_attribute?)} def @object.respond_to?(method_name, include_private=false) __model_class_has_column?(method_name) ? true : super end unless #{stubs.has_key?(:respond_to?)} def @object.method_missing(m, *a, &b) respond_to?(m) ? null_object? ? self : nil : super end def @object.class #{model_class} end unless #{stubs.has_key?(:class)} def @object.to_s "#{model_class.name}_#{to_param}" end unless #{stubs.has_key?(:to_s)} CODE yield m if block_given? end end