README.md in active_mocker-1.5.2 vs README.md in active_mocker-1.6

- old
+ new

@@ -3,23 +3,29 @@ [![Build Status](https://travis-ci.org/zeisler/active_mocker.png?branch=master)](https://travis-ci.org/zeisler/active_mocker) [![Code Climate](https://codeclimate.com/github/zeisler/active_mocker.png)](https://codeclimate.com/github/zeisler/active_mocker) [![Dependency Status](https://gemnasium.com/zeisler/active_mocker.svg)](https://gemnasium.com/zeisler/active_mocker) [![Gitter chat](https://badges.gitter.im/zeisler/active_mocker.png)](https://gitter.im/zeisler/active_mocker) -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 definition and the defined methods on a model then saves a ruby file that can be included within a test. Mocks are regenerated when the schema is modified so your mocks will not go stale. This prevents the case where your units tests pass but production code is failing. +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 definition and the defined methods on a model then saves a ruby file that can be included within a test. The mock can be run by themselves and run with a partial implementation of ActiveRecord. 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 is failing. -Example from a real app +Examples from a real apps Finished in 0.54599 seconds 190 examples, 0 failures + +------ + + Finished in 1 seconds + 374 examples, 0 failures ------------------------------------------ + +* [Documentation](#documentation) * [Contact](#contact) * [Installation](#installation) * [Setup](#setup) - * [Configuration](#overwrite_defaults_configuration) * [Generate](#generate_mocks) * [Dependencies](#dependencies) * [Usage](#usage) * [Mocking Methods](#mocking-methods) * [Managing Mocks](#managing-mocks) @@ -27,10 +33,16 @@ * [Known Limitations](#known-limitations) * [Inspiration](#inspiration) * [Contributing](#contributing) +--------------------------- + +## Documentation + +[rdoc](http://rdoc.info/github/zeisler/active_mocker/master/ActiveMocker) + ------------------------------------------ ## Contact Ask a question in the [chat room](https://gitter.im/zeisler/active_mocker). @@ -57,19 +69,10 @@ * Requires Ruby MRI =< 2.1. ## Setup -### Overwrite defaults configuration - - ActiveMocker::Generate.configure do |config| - config.schema_file = File.join(Rails.root, 'db/schema.rb') - config.model_dir = File.join(Rails.root, 'app/models') - config.mock_dir = File.join(Rails.root, 'spec/mocks') - config.logger = Rails.logger - end - ### 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 @@ -103,30 +106,48 @@ def self.bar end end ------------------ +----------------- + +### Using With Rspec, --tag active_mocker:true - #person_spec.rb + 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 + +---------- - require 'spec/mocks/person_mock.rb' - require 'spec/mocks/account_mock.rb' +* Assigning the tag `active_mocker:true` will stub any ActiveRecord model Constants for Mock classes in `it` or `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 `mock_class('ClassName')`. +* Will call `ActiveMocker::LoadedMocks.delete_all` in `after(:all)` block to clean up mock state for other tests. - PersonMock.column_names +--------- + + Person.column_names => ["id", "account_id", "first_name", "last_name", "address", "city"] - person_mock = PersonMock.new( first_name: "Dustin", + person = Person.new( first_name: "Dustin", last_name: "Zeisler", account: AccountMock.new ) => "#<PersonMock id: nil, account_id: nil, first_name: "Dustin", last_name: "Zeisler, address: nil, city: nil>" - person_mock.first_name + person.first_name => "Dustin" ### When schema.rb changes, the mock fails -(Requires a regeneration of the mocks files.) +(After `rake db:migrate` is called the mocks will be regenerated.) #db/schema.rb ActiveRecord::Schema.define(version: 20140327205359) do @@ -140,40 +161,44 @@ end -------------- - #person_spec.rb + Person.new(first_name: "Dustin", last_name: "Zeisler") + =>#<UnknownAttributeError unknown attribute: first_name > - PersonMock.new(first_name: "Dustin", last_name: "Zeisler") - =>#<RuntimeError Rejected params: {"first_name"=>"Dustin", "last_name"=>"Zeisler"} for PersonMock> - ## Mocking Methods ### Class Methods - PersonMock.bar('baz') + Person.bar('baz') => RuntimeError: ::bar is not Implemented for Class: PersonMock # Rspec 3 Mocks - allow(PersonMock).to receive(:bar) do |name, type=nil| - "Now implemented with #{name} and #{type}" + + 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 -### Instance Methods + 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 - PersonMock.new.bar('foo', 'type') - => "Now implemented with foo and type" - # Rspec 3 Mocks - allow_any_instance_of(PersonMock).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 @@ -186,13 +211,11 @@ end -------------- - #person_spec.rb - - person_mock.new.bar('foo', 'type') + Person.new.bar('foo', 'type') => ArgumentError: wrong number of arguments (2 for 1) ---------------- #app/models/person.rb @@ -206,80 +229,51 @@ end -------------- - #person_spec.rb - # Rspec 3 Mocks - allow(person_mock).to receive(:bar) do |name, type=nil| + 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. -### Managing Mocks +* Any locally defined modules will not be included or extended. -Rspec Tag - active_mocker:true +--------------- - describe 'Example', active_mocker:true do - + class Person < ActiveRecord::Base + CONSTANT_VALUE = 13 end - - Assigning this tag will stub any ActiveRecord model Constants for Mock classes in any `it's` or `before(:each)`. To stub any Constants in `before(:all)`, `after(:all)` use `mock_class('ClassName')`. -Deletes All Records and Clears Mocked Methods - - PersonMock.clear_mock - -Clears all Loaded Mocks - (Use in after(:all) to keep state from leaking to other tests.) - - ActiveMocker::LoadedMocks.clear_all - -Deletes All Records for Loaded Mocks - (Useful in after(:each) to clean up state between examples) - - ActiveMocker::LoadedMocks.delete_all - -List All Loaded Mocks - - ActiveMocker::LoadedMocks.all - => { 'PersonMock' => PersonMock } - -Map The Mock Class to it's Model - - ActiveMocker::LoadedMocks.class_name_to_mock - => { 'Person' => PersonMock } - - - -### Constants and included and extended Modules are Available. - - #app/models/person.rb - - class User < ActiveRecord::Base - CONSTANT_VALUE = 13 - end - ----------------------- - #user_spec.rb + PersonMock::CONSTANT_VALUE + => 13 - require 'spec/mocks/user_mock.rb' - UserMock::CONSTANT_VALUE - => 13 +### Scoped Methods +* As long the mock file that holds the scope method is required it will be available but implemented. -### Mocked Class - - UserMock.mocked_class - => 'User' +### 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 **class methods** * new * create/create! * column_names/attribute_names + * delete_all/destroy_all + +**Query Methods** + * all * find * find_by/find_by! * find_or_create_by * find_or_initialize_by * where(conditions_hash) @@ -287,65 +281,62 @@ * where.not(conditions_hash) * delete_all/destroy_all * delete_all(conditions_hash) * destroy(id)/delete(id) * update_all - * 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 + +**Relation Methods** + * concat + * include + * push + * clear + * take + * empty? + * replace + * any? + * many? **instance methods** * attributes * update * save/save! * write_attribute/read_attribute - (protected, can be used within modules) * delete + * new_record? + * persisted? + * reload -**has_one/belongs_to** +**has_one/belongs_to/has_many** * build_< association > * create_< association > * create_< association >! - -**has_many associations/Collections** - - * empty? - * length/size/count - * uniq - * replace - * first/last - * concat - * include - * push - * clear - * take - * average(:field_name) - * minimum(:field_name) - * maximum(:field_name) - * sum(:field_name) - * find - * find_by/find_by! - * where(conditions_hash) - * where(key: array_of_values) - * where.not(conditions_hash) - * update_all - * delete_all - * order(:field_name) - * reverse_order - * limit * < association >.create * < association >.build + ### Schema/Migration Option Support * All schema types are supported and coerced by [Virtus](https://github.com/solnic/virtus). If coercion fails the passed value will be retained. -* Default value -* Scale and Precision not supported. +* Default value is supported. +* Scale and Precision are not supported. ### Known Limitations * Model names and table names must follow the default ActiveRecord naming pattern. -* Whatever associations are setup in one mock object will not reflected in any other objects. +* Whatever associations are setup in one mock object will not be reflected in any other objects. + * There partial support for this feature coming in v1.6 when `ActiveMocker::Mock.config.experimental = true` is set. + * Validation are not present in mocks. * Sql queries, joins, etc will never be supported. ## Inspiration Thanks to Jeff Olfert for being my original inspiration for this project.