How do I use mock_models with RSpec outside of Rails? - ruby

I am currently working on a Ruby project that comprises of a Redis DB, EventMachine and Sinatra (for a lightweight API). We're using RSpec for our testing and up until this point, everything has been going great.
Now, however, we need to start talking (minimally) to a MySQL database. We've decided to go the route of ActiveRecord (just because it's SO nice!) and everything is going smooth so far. However, we are running into a small problem with our tests. I found some resources online using mock_model and mock with RSpec but, I keep getting:
undefined method `mock_model'
undefined method `mock'
errors. What gem to I need to use for these to work without installing the entire Rails framework (just seems like overkill).
OR
What other mocking/stubing methods/gems should I be using to mock my AR models? I really enjoy the flexibility of a syntax like:
#user = double(NS::UserAccount)
#car = double(NS::Car)
NS::UserAccount.stub(:find).with(#valid_user_id).return(#user)
NS::Car.stub(:find).with(#valid_car_id).return(#car)
UPDATE
My Gemfile looks like the following:
group :test do
gem 'rspec', '~> 2.8.0'
gem 'rspec-expectations', '~> 2.8.0'
gem 'rspec-mocks', '~> 2.8.0'
gem 'autotest-standalone'
gem 'em-spec', '~> 0.2.6'
gem 'rack-test', '~> 0.6.1'
gem 'factory_girl', '~> 3.1.0'
end
Also, at the top of the spec_helper.rb file, I have the following:
require 'bundler/setup'
Bundler.require(:test, :development)

For the Active Record models RSpec has method mock_model, which automatically creates several stubs, common for all Ruby on Rails models, and accepts hash.
So to use mock_model outside of Rails you should have connected Active Record and rspec-rails extension.
To make sure you can look at here where's mock_model is defined.

Related

No require 'date' statement on my ruby file but I can call DateTime.now

I am trying to understand how importing files in ruby works. But I almost spent a whole day
figuring out why I can call DateTime.now in my class where I didn't require 'date, these are all running on docker container instance where I get ruby 3.0.3
What got me stuck is when I tried to make a new ruby file on a new docker container instance ruby 3.0.3. And try calling DateTime.now it doesn't work.
I tried looking for require statement that has the word date in it in the project where I can call DateTime.now but no luck finding.
gem file of the project where I can call DateTime without require statement
gem 'aws-sdk-s3', '~> 1.93'
gem 'mime-types'
gem 'optparse', '~> 0.1.0'
group :development do
gem 'rubocop', '~> 1.12'
end
group :test do
gem 'rspec', '~> 3.10'
gem 'rubocop-rspec', '~> 2.2'
gem 'webmock', '~> 3.12'
end
gem file of the new project where I couldn't call DateTime without require statement
gem 'mime-types'
gem 'optparse', '~> 0.1.0'
gem 'gqli'
group :development do
gem 'rubocop', '~> 1.12'
end
group :test do
gem 'rspec', '~> 3.10'
gem 'rubocop-rspec', '~> 2.2'
gem 'webmock', '~> 3.12'
gem 'test-unit', '~> 3.0'
end
the only difference is the aws and gqli in both project but I tried having both of them have the same gem file it still doesn't work.
When you require the aws-sdk-s3 library, which is part of the aws-sdk-s3 Gem, the library, in turn, requires the aws-sdk-core library:
# frozen_string_literal: true
# WARNING ABOUT GENERATED CODE
#
# This file is generated. See the contributing guide for more information:
# https://github.com/aws/aws-sdk-ruby/blob/version-3/CONTRIBUTING.md
#
# WARNING ABOUT GENERATED CODE
require 'aws-sdk-kms'
require 'aws-sigv4'
require 'aws-sdk-core'
#↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
The aws-sdk-core library, which is part of the aws-sdk-core Gem, in turn, loads the param_converter library using Kernel#require_relative, as you can see here:
# client modules
require_relative 'aws-sdk-core/client_stubs'
require_relative 'aws-sdk-core/async_client_stubs'
require_relative 'aws-sdk-core/eager_loader'
require_relative 'aws-sdk-core/errors'
require_relative 'aws-sdk-core/pageable_response'
require_relative 'aws-sdk-core/pager'
require_relative 'aws-sdk-core/param_converter'
#↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
The param_converter library then, in turn, loads the date library:
# frozen_string_literal: true
require 'stringio'
require 'date'
#↑↑↑↑↑↑↑↑↑↑↑↑↑
The aws-sdk-core Gem does not depend on the date Gem:
> spec.add_dependency('jmespath', '~> 1', '>= 1.6.1') # necessary for secure jmespath JSON parsing
> spec.add_dependency('aws-partitions', '~> 1', '>= 1.651.0') # necessary for new endpoint resolution
> spec.add_dependency('aws-sigv4', '~> 1.5') # necessary for making Aws::STS, SSO, SSOOIDC API calls
> spec.add_dependency('aws-eventstream', '~> 1', '>= 1.0.2') # necessary for binary eventstream
But you don't have to depend on the date Gem in order to use the date library, because the date Gem is a default Gem, which means it is part of Ruby's standard library, gets maintained by the Ruby developers, doesn't need to be installed, doesn't need to be listed as a Gem dependency, and doesn't need to be activated.
So, that's why you don't have to require the date library yourself: because you require a library, which in turn requires another library, which in turn require_relatives another library, which in turn requires the date library.
But the more interesting question is, should you require the date library? And the answer is, Yes, you should. Relying on a require chain like this is extremely brittle: what if some library somewhere in the middle down this chain decides to change its internal structure and, e.g. validate dates using a different library or implement date validation themselves? Then your code breaks for no apparent reason.
The rule that I generally follow is that every script must stand on its own, i.e. every script must require all of its dependencies.
Now, in larger applications, this might get annoying, and might even lead to high startup latencies. A good example would be framework or a DSL, where it is simply expected that the framework or the DSL provides a set of libraries for you that are already pre-loaded. Imagine, you had to require every active_support library, active_model library, active_relation library, etc. you are using in a Ruby on Rails application. That would be stupid: if you write a Ruby on Rails model, you know that active_model is loaded, you don't need to load it again.
So, a slightly relaxed rule is: every script that is intended to be required or executed by a client must stand on its own. Scripts that are internal to the application may rely on internal knowledge about which libraries are already required.

Create an extensible Ruby gem

I'm building a gem that provides a binary. This binary uses the gem's library.
I would like to make it possible to extend the features of the gem by installing other gems.
Let's say the gem is called xyz. I would like to be able to create the xyz-nice_feature that adds a nice feature.
When using a project like Rails it's ok to add dependencies in a Gemfile but in my case it's for end-users so no Gemfile.
What would be your way of doing this ?
And another question would be how to handle different versions of the extensions.
For the moment I have the following code to load the gems, but that's it:
Gem::Specification.find_all { |s| s.name =~ /xyz-.*/ }.map(&:name).uniq.each do |gem_name|
gem gem_name, '>= 0'
end
Thank you :)

uninitialized constant StoreController::Yajl Rails app

I've included the yajl gem in my Gemfile via gem 'yajl-ruby', '~> 1.1.0' however upon calling parser = Yajl::Parser.new in my store controller I receive the error uninitialized constant StoreController::Yajl
If I execute require 'yajl' at the beginning of the controller all is well but I was under the impression that the gem should be available to controllers within the application simply by including in the gem file.
You have to indicate to Bundler the main file of the gem with the require option:
gem 'yajl-ruby', '~> 1.1.0', require: 'yajl'
This is necessary for gems whose name is different that their main file name.
See the Gemfile manual.

How can I run a gem's tests when using bundler

I have a private gem (built with jeweler) hosted on Github. I run unit tests before I commit but I'd like to test everything works when I use bundler from the end-user side.
So far I've just been creating a test environment with two files:
Gemfile:
gem 'my_gem', :git => 'git#github.com:my_repo/my_gem.git'
main.rb:
require "rubygems"
require "bundler/setup"
require "my_gem"
# Some code calling arbitrary methods from my gem
It seems like there's probably a way for me to run the unit tests built in to the gem.
Bundler supports the use of gemspecs for development. You can change your gemfile to the following:
source "http://www.rubygems.org"
gemspec
This will allow you to access all the gems you would need as a client of the gem you're building. Then in your test file you can just:
require "my_gem"
You can find more information in Yehuda's post.

undefined method `has_attached_file error paperclip

I am trying to use paperclip without rails(but trying to connect db created by rails).
Using bundler to require gems.
here are my models
class RailsDB < ActiveRecord::Base
establish_connection $db_config[:rails_db]
end
class VoiceCall < RailsDB
belongs_to :campaign
set_table_name :voice_calls
has_attached_file :sound_file
validates_attachment_presence :sound_file
end
If I try to run the program it throws the error
undefined method `has_attached_file
any idea y?
Edit:
my gem file
source "http://rubygems.org"
gem 'activerecord', '< 3.1', :require => 'active_record'
gem 'mysql2', '< 0.3'
gem "paperclip", "~> 2.4"
I require gems using
require "bundler/setup"
Bundler.require(:default)
One more observation. I started irb and required active record and then paperclip. and ran this
p ActiveRecord::Base.methods.select{|m| m =~ /has_attached_file/}
It returns empty list.
but when I open rails console (using "rails c") the statement works and returns the value.( Both are using same gems)
This error means the Paperclip gem is not loaded correctly (or at all) within your application.
Can you post your Gemfile and config/preinitializer.rb?
Is bundler working to successfully load other Gems in your environment?
I've seen this happen when Bundler was not configured correctly for a Rails project causing gems to fail to load. The paperclip model references are the canary in the coal-mine for this larger problem.
had the same issue.
using
gem "paperclip", :git => "git://github.com/thoughtbot/paperclip.git"
instead helped out.

Resources