Rails + Rspec: Test says value of variable is nil, console says otherwise - ruby-on-rails

I have a test that's failing for a custom non active record class I'm writing:
test:
describe "#xml_for_initial_request" do
it "calls the access_request method" do
ups_shipping = UpsShipping.new
ups_shipping.should_receive(:credentials)
ups_shipping.print_xml
end
end
console:
Failures:
1) UpsShipping#xml_for_initial_request calls the access_request method
Failure/Error: ups_shipping.print_xml
NoMethodError:
undefined method `to_xml' for nil:NilClass #<-- FAILURE HERE
# ./app/models/ups_shipping.rb:14:in `print_xml'
# ./spec/models/ups_shipping_spec.rb:465:in `block (3 levels) in <top (required)>'
Finished in 0.45009 seconds
1 example, 1 failure
This occurs in this model:
require 'net/https'
require 'uri'
class UpsShipping
attr_reader :products, :purchase
def initialize(options = {})
#products = options.fetch(:products, [])
#purchase = options[:purchase]
end
def print_xml
xml = ''
xml << credentials.to_xml #<-- ERROR OCCURS HERE
return xml
end
def credentials #<-- CREDENTIALS COMES FROM HERE
{
"AccessLicenseNumber" => UPS_API["access_key"],
"UserId" => UPS_API["user_id"],
"Password" => UPS_API["password"]
}
end
....
However, when I try this in the console in the test environment it works:
Nets-Mac-Pro:myproject emai$ RAILS_ENV=test bundle exec rails c --sandbox
/Users/emai/.rvm/gems/ruby-1.9.3-p362#myproject/gems/ruby-debug-ide-0.4.18/lib/ruby-debug-ide/command.rb:27: warning: already initialized constant DEF_OPTIONS
Loading test environment in sandbox (Rails 3.2.13)
Any modifications you make will be rolled back on exit
1.9.3p362 :001 > ups_shipping = UpsShipping.new
=> #<UpsShipping:0x007feb0c974790 #products=[], #purchase=nil>
1.9.3p362 :002 > ups_shipping.print_xml
=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hash>\n <AccessLicenseNumber>xxxxx</AccessLicenseNumber>\n <UserId>xxxx</UserId>\n <Password>xxx</Password>\n</hash>\n"
1.9.3p362 :003 > ups_shipping.credentials
=> {"AccessLicenseNumber"=>"xxxx", "UserId"=>"xxxx", "Password"=>"xxxx"}
What's the deal???

should_receive is intercepting the method call and not calling the original and, by default, returning nil. Add a call to and_call_original:
ups_shipping.should_receive(:credentials).and_call_original

Related

Resque Worker: Objects and methods not available in worker

I have the following worker in my web app
class TweetSender
#queue = :tweets_queue
def self.perform(tweet_id)
message = Tweet.where(:status_id => 0).order(:created_at, :id).limit(1)
message.update_attribute(status_id = 1)
$client.update(message.text)
end
end
It gets schedueled by the following resque-scheduler tweet_scheduler.yml
tweet_sender:
cron: "0 20 * * * Europe/Stockholm"
class: "TweetSender"
queue: tweets_queue
args: tweet_id
description: "This job sends daily tweets from the content db"
Which gets defined by he resque.rake
require 'resque/tasks'
require 'resque/scheduler/tasks'
task 'resque:setup' => :environment
namespace :resque do
task :setup do
require 'resque'
end
task :setup_schedule => :setup do
require 'resque-scheduler'
Resque.schedule = YAML.load_file('tweet_schedule.yml')
require 'jobs'
end
task :scheduler => :setup_schedule
end
In the resque web interface I get the following error
Exception
NoMethodError
Error
undefined method `update_attribute' for #<Tweet::ActiveRecord_Relation:0x839ca814>
/home/jan/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/relation/delegation.rb:136:in `method_missing'
/home/jan/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/relation/delegation.rb:99:in `method_missing'
/home/jan/Documents/social/app/jobs/tweet_sender.rb:6:in `perform'
I alos tried implementing the tweet_sender.rb without the update_atttribute methods like so:
class TweetSender
#queue = :tweets_queue
def self.perform(tweet_id)
message = Tweet.where(:status_id => 0).order(:created_at, :id).limit(1)
message.status_id = 1
message.save
$client.update(message.text)
end
end
And the get the following error:
Exception
NoMethodError
Error
undefined method `status_id=' for #<Tweet::ActiveRecord_Relation:0x83195bf8>
/home/jan/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/relation/delegation.rb:136:in `method_missing'
/home/jan/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-4.2.0/lib/active_record/relation/delegation.rb:99:in `method_missing'
/home/jan/Documents/social/app/jobs/tweet_sender.rb:6:in `perform'
Why are my methods and the standard rails emthods no available in my worker? Do I need to explicitly require them somewhere?
limit returns an instance of ActiveRecord::Relation.
What you really want to get is an instance of Tweet model.
Use first:
message = Tweet.where(status_id: 0).order(:created_at, :id).first

Minitest: rake test:all fails while explicit testing does not

I have a weird problem which is bugging me for days now... and I don't have a single clue.
I have a rails 4 app which i test using Minitest and guard. So far everything went fine until at some point (which unfortunately I'm not able to reconstruct although I was using guard, maybe my collaborators introduced the issues...) some of our tests fail. The weird thing is: bundle exec rake test:all fails:
DEPRECATION WARNING: rake test:all is deprecated and will be removed in Rails 5. Use rake test to run all tests in test directory. (called from mon_synchronize at /usr/lib/ruby/2.3.0/monitor.rb:214)
# Running tests with run options --seed 53809:
WARNING: The next major version of capybara-webkit will require at least version 5.0 of Qt. You're using version 4.8.7.
............EE....EE.............F..
Finished tests in 26.018707s, 1.3836 tests/s, 1.6142 assertions/s.
Error:
PlaceTest#test_return_''_if_too_many_characters_to_translate:
NoMethodError: undefined method `failsafe_translate' for nil:NilClass
test/models/place_auto_translation_test.rb:29:in `block in <class:PlaceTest>'
Error:
PlaceTest#test_test_places_are_valid:
NoMethodError: undefined method `geocode' for nil:NilClass
test/models/place_geocode_test.rb:21:in `block in <class:PlaceTest>'
Error:
PlaceTest#test_should_translate_text_below_character_limit:
NoMethodError: undefined method `failsafe_translate' for nil:NilClass
test/models/place_auto_translation_test.rb:34:in `block in <class:PlaceTest>'
Error:
PlaceTest#test_can_translate_if_valid_credentials_given:
NoMethodError: undefined method `bing_translator' for nil:NilClass
test/models/place_auto_translation_test.rb:16:in `block in <class:PlaceTest>'
Failure:
Index page Feature Test#test_0002_language is switched to german [/home/blubber/software_projects/rails/workspace/lberg-map/test/features/index_page_test.rb:16]
Minitest::Assertion: Expected to include "Neuer Ort".
36 tests, 42 assertions, 1 failures, 4 errors, 0 skips
Now, while trying to understand the issues raised I was testing the problematic files individually (within my editor and guard or on the command-line, same thing of course) it turns out, that there is actually no problem at all, all tests pass oO. Hence bundle exec rake test test/models/place_auto_translation_test.rb returns
# Running tests with run options --seed 55164:
.....
Finished tests in 25.472545s, 0.1963 tests/s, 0.2355 assertions/s.
5 tests, 6 assertions, 0 failures, 0 errors, 0 skips
Same goes for place_geocode_test.rb as well as the "failing" feature test. Any idea on what's happening here? The test file test/models/place_auto_translation_test.rb looks like this:
require_relative '../test_helper'
class PlaceTest < ActiveSupport::TestCase
def setup
#valid_translator = BingTranslatorWrapper.new(ENV['bing_id'], ENV['bing_secret'], ENV['microsoft_account_key'])
#place = Place.new(name: 'Kiezspinne',
street: 'Schulze-Boysen-Straße',
house_number: '13',
postal_code: '10365',
city: 'Berlin',
description_en: 'This is a test')
end
# AUTO TRANSLATION WRAPPER TESTS
test 'can translate if valid credentials given' do
assert_not_nil #valid_translator.bing_translator
end
test 'cannot translate if API id and key invalid or no microsoft account key' do
invalid_translator = BingTranslatorWrapper.new(ENV['wrong_id'], ENV['wrong_secret'], ENV['microsoft_account_key'])
assert_nil invalid_translator.bing_translator
invalid_translator = BingTranslatorWrapper.new(ENV['bing_id'], ENV['bing_secret'], ENV['wrong_microsoft_account_key'])
assert_equal '', invalid_translator.failsafe_translate('Dies ist ein Test', 'en', 'de')
end
test "return '' if too many characters to translate" do
text = '13 characters' * 1000
assert_equal '', #valid_translator.failsafe_translate(text, 'en', 'de')
end
test 'should translate text below character limit' do
text = 'This is a test'
assert_equal 'Automatische Übersetzung: Dies ist ein Test', #valid_translator.failsafe_translate(text, 'en', 'de')
end
test 'should autotranslate after_create' do
#place.save
#place.reload
assert_equal "Automatische Übersetzung: Dies ist ein Test", #place.description_de
end
end
and test_helper.rb looks like this
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require 'minitest/rails'
require 'minitest/reporters'
require 'minitest/rails/capybara'
reporter_options = { color: true }
Minitest::Reporters.use!(
Minitest::Reporters::DefaultReporter.new(reporter_options),
ENV,
Minitest.backtrace_filter
)
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
end
Geocoder.configure(:lookup => :test)
Geocoder::Lookup::Test.set_default_stub(
[
{
'latitude' => 52,
'longitude' => 12,
'address' => {
'road' => 'Magdalenenstr.',
'house_number' => '19',
'postcode' => '10365',
'town' => 'Berlin',
},
'type' => 'house',
}
]
)
# allow tile loading from foreign server
Capybara::Webkit.configure do |config|
%w[a b c].each { |x| config.allow_url("tile-#{x}.openstreetmap.fr") }
end
# While testing with Javascript flag, test runs in another thread,
# thus created fixtures are not available without the following setup
class Capybara::Rails::TestCase
self.use_transactional_fixtures = false
before do
if metadata[:js]
Capybara.javascript_driver = :webkit
Capybara.current_driver = Capybara.javascript_driver
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.start
end
end
after do
if metadata[:js]
DatabaseCleaner.clean
end
Capybara.reset_sessions!
Capybara.current_driver = Capybara.default_driver
end
end
Thanks a thousand, best
Andi

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

NoMethodError for object

Here is the code
#add email of team lead of the current user
def add_the_tl_email(to_address, session_user_id)
ul = UserLevel.find_by_user_id(session_user_id)
if !ul.team.nil? && !ul.role.nil?
User.user_status('active').joins(:user_levels).where(:user_levels => {:position => 'tl',
:role => ul.role,
:team => ul.team }).each do
|u| to_address << u.email
end
end
end
The error from spec:
1) CustomersController GET customer page 'create' successful should create one customer record
Failure/Error: post 'create', :customer => #customer
NoMethodError:
undefined method `team' for nil:NilClass
# ./app/mailers/user_mailer.rb:36:in `add_the_tl_email'
# ./app/mailers/user_mailer.rb:15:in `notify_tl_dh_ch_ceo'
# ./app/controllers/customers_controller.rb:27:in `create'
# ./spec/controllers/customers_controller_spec.rb:48:in `block (5 levels) in <top (required)>'
# ./spec/controllers/customers_controller_spec.rb:47:in `block (4 levels) in <top (required)>'
team is a field in user_level. Here is the user_level in factory:
Factory.define :user_level do |level|
level.role "sales"
level.position "member"
level.team 1
level.association :user
end
In rails console, the ul.team.nil? returns either true or false on test data generated by factory.
Since team is a field in user_level, why there is error in spec like: NoMethodError:
undefined method `team' for nil:NilClass ?
Thanks.
The issues is that nil.team is not a method*
NoMethodError:
undefined method `team' for nil:NilClass
That is, ul evaluates to nil: check ul.nil? before checking ul.team.nil?... but might want to find out why the find failing to start with ;-)
Happy coding.
*This is what the real error message says, the title of the post is garbage :-/
The call in
ul = UserLevel.find_by_user_id(session_user_id)
returned nil and thus nil was assigned to ul.
So when you called
!ul.team.nil?
Ruby tried to call team on nil. nil is an instance of NilClass and there is no method named team on NilClass.

Delayed_job: Undefined method error on any call

I have a rails 3.0.5 app that was working just fine with delayed_job 2.1.4.
It's been a few weeks since I touched the app, but I just went to tweak it and noticed that delayed_job is broken. Specifically, any call to delayed_job returns an "undefined method" error on the method after delay. (eg StudentMailer.delay.student_mail('test') returns "undefined method" on "student_mail") I cannot figure out why. A few things:
Replacing StudentMailer.delay.student_mail('test') with StudentMailer.student_mail('test').deliver delivers the mail just fine.
Have not changed any gem versions on the site, they've been locked since development
RVM has been uninstalled & reinstalled
Happens across all mailer methods
Code & error below:
MAILER:
class StudentMailer < ActionMailer::Base
def course_signup(email, password, course, enrolment)
#email = email
#password = password
#course = course
#enrolment = enrolment
#student = Student.where(:email => email).first
if (#student.user.first_name && #enrolment.student.user.last_name) then
#username = #student.first_name.gsub(/[^[:alnum:]]/, '').downcase + '.' + #student.last_name.gsub(/[^[:alnum:]]/, '').downcase
else
#username = "fcuser#{#student.id}"
end
mail(:to => email, :from => ENV['ACCOUNTS_EMAIL'], :subject => "You have been enrolled as a student for #{course}", :content_type => 'text/plain')
end
end
MODEL (Mailer called on after_save)
after_create {
studentmailer = StudentMailer
#studentmailer.course_signup(self.student.email, self.purchase.course).deliver
randompass = RandomPassword.random_string(20)
randomGatewayPass = RandomPassword.random_string(8)
studentmailer.delay.course_signup(self.student.email, randomGatewayPass, self.purchase.course, self)
self.save }
CONFIG/BOOT.RB
require 'yaml'
YAML::ENGINE.yamler = 'syck'
require 'rubygems'
gemfile = File.expand_path('../../Gemfile', __FILE__)
begin
ENV['BUNDLE_GEMFILE'] = gemfile
require 'bundler'
Bundler.setup
rescue Bundler::GemNotFound => e
STDERR.puts e.message
STDERR.puts "Try running `bundle install`."
exit!
end if File.exist?(gemfile)
DELAYED JOB ERROR:
{undefined method course_signup' for #<Class:0x007fbcf61850c8>
/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/performable_mailer.rb:6:in
perform'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/backend/base.rb:87:in
invoke_job'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/worker.rb:120:in
block (2 levels) in
run'\n/Users/john/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/timeout.rb:58:in
timeout'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/worker.rb:120:in
block in
run'\n/Users/john/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/benchmark.rb:310:in
realtime'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/worker.rb:119:in
run'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/worker.rb:177:in
reserve_and_run_one_job'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/worker.rb:104:in
block in
work_off'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/worker.rb:103:in
times'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/worker.rb:103:in
work_off'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/worker.rb:78:in
block (2 levels) in
start'\n/Users/john/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/benchmark.rb:310:in
realtime'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/worker.rb:77:in
block in
start'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/worker.rb:74:in
loop'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/worker.rb:74:in
start'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/command.rb:104:in
run'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/command.rb:83:in
block in
run_process'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/daemons-1.1.4/lib/daemons/application.rb:249:in
call'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/daemons-1.1.4/lib/daemons/application.rb:249:in
block in
start_proc'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/daemons-1.1.4/lib/daemons/daemonize.rb:197:in
call'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/daemons-1.1.4/lib/daemons/daemonize.rb:197:in
call_as_daemon'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/daemons-1.1.4/lib/daemons/application.rb:253:in
start_proc'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/daemons-1.1.4/lib/daemons/application.rb:293:in
start'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/daemons-1.1.4/lib/daemons/controller.rb:70:in
run'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/daemons-1.1.4/lib/daemons.rb:195:in
block in
run_proc'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/daemons-1.1.4/lib/daemons/cmdline.rb:109:in
call'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/daemons-1.1.4/lib/daemons/cmdline.rb:109:in
catch_exceptions'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/daemons-1.1.4/lib/daemons.rb:194:in
run_proc'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/command.rb:81:in
run_process'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/command.rb:75:in
block in
daemonize'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/command.rb:73:in
times'\n/Users/john/.rvm/gems/ruby-1.9.2-p290/gems/delayed_job-2.1.4/lib/delayed/command.rb:73:in
daemonize'\nscript/delayed_job:5:in `' | 2011-09-06 07:42:21 |
NULL | 2011-09-06 07:43:00 | NULL | 2011-09-06 07:40:07 |
2011-09-06 07:43:00 |
I was Googling the same issue, and I found a fix for this(it worked for me).
add these two lines to the head of your config/application.rb
require 'yaml'
YAML::ENGINE.yamler = 'syck'
then, restart your server(webrick/thin/whatever) and delayed_job
(bundle exec ./script/delayed_job restart)
done.
I had the same problem. If you are using thin, try doing "bundle exec thin start". It worked for me.
try to change method definition
def self.course_signup
or
studentmailer = StudentMailer.new
because now you call method from class but method belongs to object

Resources