Stubbing a class level constant in rspec - ruby-on-rails

My class is structured something like this:
class Abc
ONE_CLASS_LEVEL_CONSTANT_BEING_READ_FROM_DB = GloablAttributeValue.read_from_db
def some_method_that_use_above_constant
# this function behaves differently for different values of ONE_CLASS_LEVEL_CONSTANT_BEING_READ_FROM_DB
end
end
Now i want to unit test some_method_that_use_above_constant on the basis of different values ONE_CLASS_LEVEL_CONSTANT_BEING_READ_FROM_DB .
Is this possible to stub out value of ONE_CLASS_LEVEL_CONSTANT_BEING_READ_FROM_DB, so that i can test it for different values in rspec ?

As per this doc, with the version 2.11 of Rspec this should work:
stub_const("Abc::ONE_CLASS_LEVEL_CONSTANT_BEING_READ_FROM_DB", 5)

Related

Testing a Class inside of a Module with RSpec

So, I have a module in my ruby code which looks something like this:
module MathStuff
class Integer
def least_factor
# implementation code
end
end
end
and I have some RSpec tests in which I would like to test that my Integer#least_factor method works as expected. we'll say that the tests are in the same file for simplicity. The tests look something like this:
describe MathStuff do
describe '#least_factor' do
it 'returns the least prime factor' do
expect(50.least_factor).to eq 2
end
end
end
Unfortunately, when I run the tests, I get an error like this:
NoMethodError:
undefined method `least_factor' for 50:Fixnum
Please let me know if you know how to include the MathStuff::Integer class for testing.
Note: just for clarification, I am actually trying to open up the Ruby Integer class here and add methods to it.
Your code should look like:
describe MathStuff::Integer do
describe '#least_factor' do
it 'returns the least prime factor' do
expect(MathStuff::Integer.new.least_factor).to eq 2
end
end
end
But you're calling 50.least_factor and 50 is a Fixnum object, not your MathStuff::Integer and it doesn't have that method defined.
Before the addition of refinements in Ruby 2.1 (and experimental support in 2.0), you couldn't limit the scope of a monkeypatch like this to a particular context (i.e. a module).
But the reason your example doesn't work is that defining an Integer class under the Mathstuff module creates a new class which has nothing to do with the Integer core class. The only way to override the core class is to open the class at the top level (not within a module).
I usually put core extensions in a lib/core_ext subdirectory, named after the class they are patching, in your case lib/core_ext/integer.rb.
Simple but not recomended way:
require "rspec"
class Integer
def plus_one
self + 1
end
end
describe 'MathStuff' do
describe '#plus_one' do
it 'should be' do
expect(50.plus_one).to eq 51
end
end
end
$ rspec test.rb
.
Finished in 0.01562 seconds
1 example, 0 failures

Rails: How can I know which is the tested model in unit tests?

I have a test helper with the following signature, in test_helper.rb:
assert_resolve_mapping(model_name, attrs_ary_to_exclude = [])
The first parameter is a string representing the actual model to be asserted, i.e.: User, Customer, Invoice, etc.. The second is an array of attributes.
So in my unit tests I have:
require 'test_helper'
class CustomerUnitTest < ActiveSupport::TestCase
test "should resolve mapping" do
assert_resolve_mapping("Customer", ["created_at", "updated_at"])
end
end
Since I have to call the helper in various unit tests for various models, is there a way to avoid passing the first parameter, "Customer" in this case, knowing which is the model being actually tested?
I believe you can parse the model name out of the class name.
def assert_resolve_mapping(attrs_ary_to_exclude = [])
model_name = self.class.to_s.sub(/UnitTest\Z/, "")
...
end

How to test ActiveRecord witout Rails?

I have a project in which I use ActiveRecord to store information in a sqlite db file. I'm not using Rails and AR seems to do the job perfectly. My question is how exactly to test my classes witout hitting the db? I found some gems that would to the trick (FactoryGirl, UnitRecord), but they are meant to work with Rails.
class News < ActiveRecord::Base
belongs_to :feed
def delete_old_news_if_necessary
# time_limit = Settings::time_limit
return if time_limit.zero?
News.destroy_all("date < #{time_limit}")
end
def delete_news_for_feed(feed_id)
News.destroy_all(:id => feed_id)
end
def news_for_feed(feed_id)
News.find(feed_id)
end
end
I read that i can do a column stub:
Column = ActiveRecord::ConnectionAdapters::Column
News.stubs(:columns).returns([Column.new(),...])
Is this the right way to do these tests? Also, when is it better to have a separate db just for testing and to create it, run the tests, and the delete it?
If you want to avoid hitting the db in tests I can recommend the mocha gem. It does stubs as well as it lets you define expectations.
Edit: Regarding your question on when it is better to use a test db: I would say, whenever there is no reason against it. :)
Edit: For example, you can mock News.find like this in a test:
def news_for_feed_test
# define your expectations:
news = News.new
News.expects(:find).with(1).returns(news)
# call the method to be tested:
News.new.news_for_feed(1)
end
At the same time this makes sure, find gets called exactly once. There are a lot more things Mocha can do for you. Take a look at the documentation. Btw., it looks like these methods of yours should be class methods, no?

Clearing class instance variables in between Rspec examples

I'm writing specs for a gem of mine that extends ActiveRecord. One of the things it has to do is set a class instance variable like so:
class MyModel < ActiveRecord::Base
#foo = "asd"
end
Right now when I set #foo in one it "should" {} it persists to the next one. I understand this is normal Ruby behavior but I thought RSpec had some magic that cleaned everything out in between specs. I'd like to know how I can re-use a single AR model for all my tests (since creating a bunch of tables would be a pain) while being sure that #foo is being cleared between each test. Do I need to do this manually?
I wound up generating a method in my helper class that generated new classes with Class.new, so I could be sure that nothing was being left over in between tests.
You should simply make good use of the after :each block.
after(:each) do
#foo = nil
end

how to test collections of ActiveRecords in rspec?

I like RSpec, and I really like its =~ array operator matcher to verify that an array contains a specific set of elements, regardless of ordering.
But not surprisingly, it tests pointer equality, not content equality, so the following won't work:
class Flea < ActiveRecord::Base ; end
class Dog < ActiveRecord::Base
has_many :fleas
end
#d = Dog.create
#d.fleas << (#f1 = Flea.create)
#d.fleas << (#f2 = Flea.create)
#d.fleas.should =~ [#f1, #f2]
So I find myself frequently writing this in my RSpec tests:
#d.fleas.map {|f| f.id}.should =~ [#f1.id, #f2.id]
... which reeks of bad code smell. Does RSpec provide a better way to verify a collection of ActiveRecord objects, regardless of the order returned? Or at least is there a prettier way to code such a test?
ActiveRecord::Relations don't work like Arrays (as you found out). See Issue #398 on the GitHub RSpec-Rails Issue board.
The answer is to add this line of code to your spec_helper.rb:
RSpec::Matchers::OperatorMatcher.register(ActiveRecord::Relation, '=~', RSpec::Matchers::MatchArray)

Resources