clean-mock

Clean and efficient ruby testing object creation helper/mocking library with interface similar to FactoryBot


License
MIT
Install
gem install clean-mock -v 0.1.0

Documentation

Clean mock - ruby testing mock and stub helper

Clen mock replaces fixtures in tests. This way, you won't have to keep the fixtures up-to-date as you change the data model.

Clen mock generates data on the fly and adding and removing fields is much easier. Also, you can use it in setup just how you'd use fixtures.

Mocks you create will use objects that you allready have, as for example ActiveRecord or Sequel models.

Library is similar to factory bot, but creates object in much cleaner - non-magic way. Pointer to newely created object is passed and you are free to do with it as you please.

Why?

There is no method_missing inside clean-mock lib. Author (@dux) loves metaprograming, but thinks that this is not place to use it, hence this lib and not factory bot.

Using clean-mock will probably never produce unexpected results and you will not have to work around it in any way.

Installation and usage

to install

gem install clean-mock

or in Gemfile

gem 'clean-mock'

and to use

require 'clean-mock'

Dependency

clean-mock requires that you have String#classify and String#constantize defined.

mock.define

Makes definitinos/descriptions of base mock objects. We start with new object and reference is passed.

mock.define(:user) do |user, opts| ... - define mock object and use User class instance

mock.define(:user, class: SomeClass) do |user, opts| ... - use SomeClass instead of calculated User

mock.define(:user, class: :some_class) do |some_class, opts|... - dynamicly create SomeClass and use it

mock.define(:user, class: false) do |opts| ... - do not create a class on mock.build, pass only options

CleanMock instance methods, available inside define &block

Only the basic helper stuff is available.

trait(name, &block) - Create different versions of a object

func(name, &blok) - shortcut for @object.define_method, overload or add class methods

sequence(name) - create a named sequence

create(name, [field]) - create and link other objects

All features shown as examples in Example 1.

mock - other public methods

mock.build(:user) -> build user object, no save

mock.create(:user) -> build user object and save if @object.respond_to?(:save) == true

mock.fetch(:user) -> create or fetch allready created object

mock.attributes_for(:user, :trait1, ...) -> get attrbibutes for created object

Example 1 - object with a trait and an option

Fast reference for a start. In this case class name is calculated as (:user).to_s.classify

# define user mock wich will use existing User model for creation of new objects
mock :user do |user, opts|
  user.name    = 'User %s' % sequence(:foo)
  user.address = 'Somewhere %s' % sequence
  user.email   = opts[:email] || Faker::Internet.email

  trait :admin do
    func :say_ok do
      'ok'
    end

    # or the same thing
    def user.say_ok
      'ok'
    end

    user.is_admin = true
  end

  trait :with_org do
    create :org # shortcut for user.org_id = mock.create(org).id
  end

  after_create do
    # stuff to run afte create
    # user should have id and access to opts is available
  end
end

# this will create User model but will not save
user = mock.build :user
user.class    # User
user.id.class # NilClass
user.name     # 'User 1'
user.email    # 'john.doe@from-faker-gem.net'
user.say_ok   # ArgumentError
user.is_admin # false
user.org      # nil

# this creates and saves new User model
user = mock.create :user, :admin, email: 'foo@bar.baz'
user.name     # 'User 2'
user.email    # 'foo@bar.baz'
user.say_ok   # 'ok'
user.is_admin # true
user.org      # nil

# now we will create another mocked object inside base one
user = mock.create :user, :with_org
user.name     # 'User 3'
user.email    # 'john.doe@from-faker-gem.net'
user.say_ok   # ArgumentError
user.is_admin # false
user.org      # <Org>

Example 2 - custom class as a class

In this case class User is given and calculated one AdminUser will not be used.

mock :admin_user, class: User do |user, opts|
  user.is_admin = true
end

mock.create :admin_user # <User:0x0...>

Example 3 - class: false

With passing class: false you can return anything you like and you will not be using base class.

mock do
  # return new generic class
  define :foo, class: false do
    Class.new do
      def foo
        :bar
      end
    end.new
  end

  # retrun random string
  define :commmon_name, class: false do
    ['John', 'Josh', 'Mike'].sample
  end
end

obj = mock.build :foo   # <Foo:0x0...>
obj.foo                 # :bar

str = mock.build :commmon_name
str                     # John, Josh or  Mike

Development

After checking out the repo, run bundle install to install dependencies. Then, run rspec to run the tests.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/solnic/clean-mock. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.