Rspec and rails: Problems while testing libraries in the lib directory - ruby-on-rails

I have some classes in the lib directory, and I want to test it. My class which I want to test looks like:
class StatAggregation
class << self
def skills_rate(user_id)
user_id = User.find_by_id(user_id)
...
end
end
end
I created spec:
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
describe StatAggregation do
fixtures [
:users
]
describe 'skills_rate method' do
it 'should work' do
#user_id = 1
#user = mock_model(User)
User.should_receive(:find_by_id).with(#user_id).and_return(#user)
...
StatAggregation.skills_rate(#user_id)
end
end
end
It works ok, but it doesn't show where appeared error:
1)
ArgumentError in 'PxStatAggregation skills_rate method should work'
wrong number of arguments (1 for 0)
script/spec:10:
Finished in 0.326331 seconds
How to get number of line where appeared error "wrong number of arguments (1 for 0)"?

Add -b or --backtrace to spec command-line or to your spec.opts file.

Related

How to remove desc messages from rspec when using thor?

Now I am using thor in a rails project.
I wrote these codes:
lib/tasks/my_task.rb
require 'thor'
module Tasks
class MyTask < Thor
desc 'My Batch', 'This is my awesome batch'
option :date
def execute(type)
# do_something
end
end
end
Tasks::MyTask.start(ARGV)
spec/lib/tasks/my_task_spec.rb
require 'spec_helper'
describe 'Test my task' do
context 'With date option' do
before do
#option = { date: '20150903' }
end
it 'Can insert to db' do
expect do
Tasks::MyTask.new.invoke(:execute, ['commit'], #option)
end.to change(ProductTable, :count).by(1)
end
end
end
The problem is when I run bundle exec rspec, it showed:
Run options: exclude {:heavy=>true}
..................................................................................................................................................................................................****************************...................................................
........................................................************.......................................................................................................................................................................................................******
Commands:
rspec help [COMMAND] # Describe available commands or one specific command
rspec My Batch # This is my awesome batch
.................................................................................................................................................................................................................................................................................
Why the desc messages been shown here? How to config to remove them?
Haven't tested it, but I'd imagine you could probably patch it out with something like:
module Thor
def puts(*args, &block)
# do nothing
end
end
EDIT: actually it looks like this might be handled a little differently here: https://github.com/erikhuda/thor/blob/master/lib/thor/shell/basic.rb
It looks like you could stub out Thor::Shell::Basic#stdout and #stderr

Printing Rails test names to find the slowest tests

I'd like to find which of the tests are the slowest in my test suite based on this blog post. Here's the minified version of the code:
# test/test_time_tracking.rb
module TestTimeTracking
class ActiveSupport::TestCase
setup :mark_test_start_time
teardown :record_test_duration
def mark_test_start_time
#start_time = Time.now
end
def record_test_duration
puts "Test class: #{self.class.name}"
puts "Duration: #{Time.now - #start_time}"
end
end
end
# test/test_helper.rb
require 'test_time_tracking'
include TestTimeTracking
# ...
Is there a way to print out the test name during either the settup or teardown? In the blog post they call name attribute in the teardown block, but this throws an error in my case. I've also tried #name and #method_name with no success.
I'm using shoulda-contexts gem on top of the default Rails test framework. I know that I can get the test name and duration with rake test TESTOPTS=-v, but I will then have to run another script to parse the output.
Use minitest-reporters. Installation Guide is provided on this page.
After configration use rspec reporter. i.e in your test_helper.rb file write
Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new()]
And run the test. This 'll format output like this:
You can see the time taken by each test.
def record_test_duration
puts "Test class: #{self.class.name}"
puts "Test method: #{self.method_name}"
puts "Duration: #{Time.now - #start_time}"
end
self.method_name will print the current test method name
Rails 5
bin/rails test -v
It prints something like this:
SimpleTest#test_: Simple should be a success. = 0.26 s = .
SimpleTest#test_: Simple should be a failure. = 0.23 s = .

how to test a the length of content in a p tag in rails unit test

I want to test the length of a string in a paragraph. Which method should I pick?
assert_select 'dd p'.length, 80
This is what I used, but it is wrong!
I would use a helper to do that truncation and a test for the helper itself instead of using an integration test.
Suppose that the method is in your users_helper.rb
module UsersHelper
def my_truncation(text)
truncate(text, length: 80)
end
end
Then you can add a test under test/helpers called users_helper_test.rb like following:
require 'test_helper'
class UsersHelperTest < ActionView::TestCase
def test_truncates_long_text
assert(my_truncation("some text" * 200).size == 80)
end
def test_does_not_truncate_short_texts
my_text = 'some text'
assert(my_truncation(my_text).size == my_text.size)
end
end
Then you can test it from the console:
ruby -I test test/helpers/users_helper_test.rb
Run options: --seed 33686
# Running:
..
Finished in 0.179856s, 11.1200 runs/s, 11.1200 assertions/s.
Which runs muuuuuch faster than an integration test.
Hope this helps

FakeFS and Rspec incosistency with Rspec and real filesystem

I'm trying to write some tests involving file operations. I want to use some fake file system (something like VCR for external services) and I have found fakeFS. Unfortunately, either I can't set it right or something is broken (which I doubt, it's quite basic function), I've prepared simple example which illustrates what I mean, let the code speak:
With real FS:
module MyModule
describe Something do
before(:all) do
File.open("#{Rails.root}/foo.txt", 'w+') { |f| f.write 'content'}
end
it 'should exist' do
expect(Pathname.new("#{Rails.root}/foo.txt").exist?).to be_true
end
it 'should still exist' do
expect(Pathname.new("#{Rails.root}/foo.txt").exist?).to be_true
end
end
end
Running that gives:
bash-4.2$ rspec
..
Finished in 0.00161 seconds
2 examples, 0 failures
Adding fakeFS in such way:
require 'fakefs/spec_helpers'
module MyModule
describe Something do
include FakeFS::SpecHelpers
FakeFS.activate!
FakeFS::FileSystem.clone(Rails.root)
before(:all) do
File.open("#{Rails.root}/foo.txt", 'w+') { |f| f.write 'content'}
end
it 'should exist' do
expect(Pathname.new("#{Rails.root}/foo.txt").exist?).to be_true
end
it 'should still exist' do
expect(Pathname.new("#{Rails.root}/foo.txt").exist?).to be_true
end
end
end
results in:
bash-4.2$ rspec
.F
Failures:
1) MyModule::Something should still exist
Failure/Error: expect(Pathname.new("#{Rails.root}/foo.txt").exist?).to be_true
expected: true value
got: false
# ./spec/models/something_spec.rb:23:in `block (2 levels) in <module:MyModule>'
Finished in 0.00354 seconds
2 examples, 1 failure
So it seems like file is not persisted through subsequent tests. Do I misunderstand how before(:all) works or do I do something wrong? If so then why that code works with real files?
If it is 'not a bug, just a feature' then is there any other fake filesystem gem which is consistent with real one? Or do I have to stay with real files to get tests that.. well, test?
I found the answer just after creating that question, duh ;) I've looked into source of that lib and found suspicious line.
Instead of FakeFS::SpecHelpers I've included FakeFS::SpecHelpers::All which is the same code except FakeFS::FileSystem is not being cleared after each call, now it behaves correctly.

Uninitialized Constant error Loading a class/module in a Rails initializer

I'm working on integrating Stripe's webhooks into a Rails app using https://github.com/integrallis/stripe_event. I'm struggling to get my code to working according to the example in the gem's docs whereby an initializer is used to dictate which code responds to a particular event. It seems that Rails isn't (auto)loading my module in the initializer.
I'm configuring the autoload path properly:
# config/application.rb
config.autoload_paths += %W(#{config.root}/lib)
The stripe initializer:
#config/initializers/stripe.rb
stripe_config = YAML.load_file(Rails.root.join('config', 'stripe.yml'))[Rails.env]
Stripe.api_key = stripe_config["secret_key"]
STRIPE_PUBLIC_KEY = stripe_config["publishable_key"]
StripeEvent.setup do
# Not sure if I need this to load my module
require 'stripe_event_handlers' # => true
subscribe 'customer.subscription.created' do |event|
StripeEventHanders.handle_customer_subscription_created(event) # Define subscriber behavior
end
end
Here's my custom module (though I've tried it as a class too):
#lib/stripe_event_handlers.rb
module StripeEventHandlers
def handle_customer_subscription_created(event) # Define subscriber behavior
puts event
end
end
This is my test:
require 'test_helper'
# --- Run this in the console to get event response for mocking ---
#serialized_object = YAML::dump(Stripe::Event.retrieve('evt_0Cizt88YP0nCle'))
#filename = Rails.root.join('test/fixtures/stripe_objects', 'customer_subscription_created.yml')
#File.open(filename, 'w') {|f| f.write(serialized_object) }
class StripeEvent::WebhookControllerTest < ActionController::TestCase
def test_mock_event
event_id = 'evt_0Cizt88YP0nCle'
event = YAML.load_file(Rails.root.join('test/fixtures/stripe_objects', 'customer_subscription_created.yml'))
Stripe::Event.expects(:retrieve).with(event_id).returns(event)
assert_equal Stripe::Event.retrieve(event_id), event
end
def test_customer_subscription_created_webhook
event_id = 'evt_0Cizt88YP0nCle'
event = YAML.load_file(Rails.root.join('test/fixtures/stripe_objects', 'customer_subscription_created.yml'))
Stripe::Event.expects(:retrieve).at_most(2).with(event_id).returns(event)
# This should be a raw post request but that doesn't seem to come through
# on the stripe_event / rails side in the params hash. For testing
# purposes, we can just use a get request as the route doesn't specify an
# HTTP method.
get :event, :use_route => :stripe_event, :id => event_id
assert_response :success
end
end
And here's my test result failure:
StripeEvent::WebhookControllerTest
ERROR (0:00:00.043) test_customer_subscription_created_webhook
uninitialized constant StripeEventHanders
# config/initializers/stripe.rb:10:in `block (2 levels) in <top (required)>'
PASS (0:00:00.053) test_mock_event
Finished in 0.055477 seconds.
2 tests, 1 passed, 0 failures, 1 errors, 0 skips, 2 assertions
You are just missing the letter l in StripeEventHandlers.
subscribe 'customer.subscription.created' do |event|
StripeEventHanders.handle_customer_subscription_created(event)
end
Also, handle_customer_subscription_created should be defined as a class method:
module StripeEventHandlers
def self.handle_customer_subscription_created(event) # Define subscriber behavior
puts event
end
end

Resources