View on GitHub

Active mocker

Create mocks from active record models without loading rails or running a database.

Download this project as a .zip file Download this project as a tar.gz file

ActiveMocker

Gem Version Build Status Code Climate Dependency Status Gitter chat

ActiveMocker creates mocks classes from ActiveRecord models. Allowing your test suite to run very fast by not loading Rails or hooking to a database. It parses the schema.rb and the defined methods on a model then generates a ruby file that can be included within a test. The mock file can be run by themselves and come with a partial implementation of ActiveRecord. Attributes and associations can be used just the same as in ActiveRecord. Methods will have the correct arguments but raise an Unimplemented error when called. Mocks are regenerated when the schema is modified so your mocks will not go stale; preventing the case where your units tests pass but production code fails.

Examples from a real apps

    Finished in 0.54599 seconds
    190 examples, 0 failures

    Finished in 1 seconds
    374 examples, 0 failures


Documentation Inline docs

rdoc


Contact

Ask a question in the chat room.


Installation

Add this line to your application's Gemfile:

gem 'active_mocker'

And then execute:

$ bundle

Or install it yourself as:

$ gem install active_mocker

Dependencies

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 bar(name, type=nil)
    puts name
  end

  def self.bar
  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


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

Class Methods

Person.bar('baz')
  => RuntimeError : :: bar is not Implemented for Class :PersonMock

# Rspec 3 Mocks

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

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"

# Rspec 3 mock class method
allow_any_instance_of(Person).to receive(:bar) do
  "Now implemented"
end

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 bar(name)
    puts name
  end

end

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

#app/models/person.rb

class Person < ActiveRecord::Base
  belongs_to :account

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

end

# Rspec 3 Mocks
allow(person).to receive(:bar) do |name, type=nil|
  "Now implemented with #{name} and #{type}"
end
=> NoMethodError : undefined method `bar' for class ` PersonMock '

Constants and Modules are Available.


class Person < ActiveRecord::Base
  CONSTANT_VALUE = 13
end

PersonMock::CONSTANT_VALUE
  => 13

Scoped Methods

Managing Mocks

Deletes All Records for Loaded Mocks - (Useful in after(:each) to clean up state between examples)

ActiveMocker::LoadedMocks.delete_all

ActiveRecord supported methods

See Documentation for a complete list of methods and usage.

class methods

Query Methods

Relation Methods

instance methods

has_one/belongs_to/has_many

Schema/Migration Option Support

Known Limitations

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