Giter VIP home page Giter VIP logo

active_mocker's Introduction

ActiveMocker

Gem Version Build Status Code Climate Dependency Status Gitter chat Gittip

Description

ActiveMocker creates mock classes from ActiveRecord models, allowing your test suite to run at breakneck speed. This can be done by not loading Rails or hitting a database. The models are read dynamically and statically so that ActiveMocker can generate a Ruby file to require within a test. The mock file can be run by itself and comes with a partial implementation of ActiveRecord. Attributes and associations can be used the same as in ActiveRecord. Methods have the same argument signature but raise a NotImplementedError when called, allowing you to stub it with a mocking framework, like RSpec. Mocks are regenerated when the schema is modified so your mocks won't go stale, preventing the case where your units tests pass but production code fails.

Examples from a real apps

	Finished in 1 seconds
	374 examples, 0 failures

Around the web

"Mocking ActiveRecord with ActiveMocker" by Envy



Documentation Inline docs

rdoc


Contact

Ask a question in the chat room.


Installation

Add this line to your application's Gemfile:

group :development, :test do
  gem 'active_mocker'
end

It needs to be in development as well as test because development is where mocks will be generated. And then execute:

$ bundle

Or install it yourself as:

$ gem install active_mocker

Dependencies

  • Tested with Rails 4.0, 4.1, 4.2
  • Requires Ruby MRI >= 2.1.

Setup

See example_rails_app for complete setup.

Generate Mocks

Running this rake task builds/rebuilds the mocks. It will be ran automatically after every schema modification. If the model changes this rake task needs to be called manually. You could add a file watcher for when your models change and have it run the rake task.

rake active_mocker:build

Usage

#db/schema.rb

ActiveRecord::Schema.define(version: 20140327205359) do

  create_table "people", force: true do |t|
    t.integer  "account_id"
    t.string   "first_name",        limit: 128
    t.string   "last_name",         limit: 128
    t.string   "address",           limit: 200
    t.string   "city",              limit: 100
  end

end

#app/models/person.rb

class Person < ActiveRecord::Base
  belongs_to :account

  def self.bar(name, type=nil)
	puts name
  end

end

Using With Rspec, --tag active_mocker:true

require 'rspec'
require 'active_mocker/rspec_helper'
require 'spec/mocks/person_mock'
require 'spec/mocks/account_mock'

describe 'Example', active_mocker:true do

  before do
	Person.create # stubbed for PersonMock.create
  end

end

  • Assigning the tag active_mocker:true will stub any ActiveRecord model Constants for Mock classes in an it or a before/after(:each). This removes any need for dependency injection. Write tests and code like you would normally.
  • To stub any Constants in before(:all), after(:all) use active_mocker.find('ClassName').
  • Mock state will be cleaned up for you in an after(:all). To clean state your self use active_mocker.delete_all.

Person.column_names
  => ["id", "account_id", "first_name", "last_name", "address", "city"]

person = Person.new( first_name:  "Dustin", 
    				 last_name:   "Zeisler", 
    				 account:      Account.new )
  => "#<PersonMock id: nil, account_id: nil, first_name: "Dustin", last_name: "Zeisler", address: nil, city: nil>"

person.first_name
  => "Dustin"

When schema.rb changes, the mock fails

(After rake db:migrate is called the mocks will be regenerated.)

#db/schema.rb

ActiveRecord::Schema.define(version: 20140327205359) do

  create_table "people", force: true do |t|
    t.integer  "account_id"
    t.string   "f_name",        limit: 128
    t.string   "l_name",        limit: 128
    t.string   "address",       limit: 200
    t.string   "city",          limit: 100
  end

end

Person.new(first_name: "Dustin", last_name: "Zeisler")
  =>#<UnknownAttributeError unknown attribute: first_name >

Mocking Methods

Rspec 3 Mocks - verify double

Verifying doubles are a stricter alternative to normal doubles that provide guarantees about what is being verified. When using verifying doubles, RSpec will check that the methods being stubbed are actually present on the underlying object if it is available. rspec-mocks/docs/verifying-doubles

RSpec.configure do |config|
  config.mock_framework = :rspec
  config.mock_with :rspec do |mocks|
    mocks.verify_doubled_constant_names = true
    mocks.verify_partial_doubles = true
  end
end
Person.bar('baz')
  => NotImplementedError: ::bar is not Implemented for Class :PersonMock. To continue stub the method.

allow(Person).to receive(:bar) do |name, type=nil|
  "Now implemented with #{name} and #{type}"
end

Person.bar('foo', 'type')
=> "Now implemented with foo and type"

When the model changes, the mock fails

(Requires a regeneration of the mocks files.)

#app/models/person.rb

class Person < ActiveRecord::Base
  belongs_to :account

  def self.bar(name)
    puts name
  end

end

Person.bar('foo', 'type')
  => ArgumentError: wrong number of arguments (2 for 1)

#app/models/person.rb

class Person < ActiveRecord::Base
  belongs_to :account

  def self.foo(name, type=nil)
    puts name
  end

end

allow(Person).to receive(:bar) do |name, type=nil|
  "Now implemented with #{name} and #{type}"
end
=> RSpec::Mocks::MockExpectationError: PersonMock does not implement: bar

Constants and Modules

  • Any locally defined modules will not be included or extended. It can be disabled by ActiveMocker::Config.disable_modules_and_constants = true

class Person < ActiveRecord::Base
  CONSTANT_VALUE = 13
end

PersonMock::CONSTANT_VALUE
  => 13

Scoped Methods

  • Any chained scoped methods will be available when the mock file that defines it is required. When called it raises a NotImplementedError, stub the method with a value to continue.

Managing Mocks

require "active_mocker/rspec_helper"

active_mocker.delete_all # Delete all records from loaded mocks

active_mocker.find("User") # Find a mock by model name. Useful in before(:all)/after(:all) where automatic constant stubbing is unavailable.

active_mocker.mocks.except("User").delete_all # Delete all loaded mock expect the User mock.

ActiveRecord supported methods

See Documentation for a complete list of methods and usage.

Class Methods - docs

  • new
  • create/create!
  • column_names/attribute_names
  • delete_all/destroy_all
  • table_name
  • slice
  • alias_attributes

Query Methods - docs

  • all
  • find
  • find_by/find_by!
  • find_or_create_by
  • find_or_initialize_by
  • where(conditions_hash)
  • where(key: array_of_values)
  • where.not(conditions_hash)
  • delete_all/destroy_all
  • delete_all(conditions_hash)
  • destroy(id)/delete(id)
  • update_all
  • update(id, attributes)
  • count
  • uniq
  • first/last
  • average(:field_name)
  • minimum(:field_name)
  • maximum(:field_name)
  • sum(:field_name)
  • order(:field_name)
  • reverse_order
  • limit
  • none

Relation Methods - docs

  • concat
  • include
  • push
  • clear
  • take
  • empty?
  • replace
  • any?
  • many?

instance methods - docs

  • attributes
  • update
  • save/save!
  • write_attribute/read_attribute - (protected, can be used within modules)
  • delete
  • new_record?
  • persisted?
  • reload
  • attribute_names
  • attribute_present?
  • has_attribute?
  • slice
  • attribute_alias?
  • alias_attributes

has_one/belongs_to/has_many

  • build_< association >
  • create_< association >
  • create_< association >!
  • < association >.create
  • < association >.build

Schema/Migration Option Support

  • A db/schema.rb is not required.
  • All schema types are supported and coerced by Virtus. If coercion fails the passed value will be retained.
  • Default value is supported.
  • Scale and Precision are not supported.

Known Limitations

  • Namespaced modules are not currently supported.
  • When an association is set in one object it may not always be reflective in other objects, especially when it is a non standard/custom association. See test_rails_4_app/spec/active_record_compatible_api.rb for a complete list of supported associations.
  • Validation/Callbacks are not supported.
  • Sql queries, joins, etc will never be supported.
  • A record that has been created and then is modified will persist changes without calling #save, beware of this difference.
  • This is not a full replacement for ActiveRecord.
  • Primary key will always default to id. If this is an causes a problem open an issue.

Inspiration

Thanks to Jeff Olfert for being my original inspiration for this project.

Contributing

Your contribution are welcome!

  1. Fork it ( http://github.com/zeisler/active_mocker/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

active_mocker's People

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.