I am doing my testing with mocks and stubs but I keep getting nil in my output. I am not sure if it's the problem with the assigns method. Could I also know how I should debug this kind of problem? I am using rspec-rails 3.5.2 Thank you.
The failing test:
describe 'guest user' do
describe 'GET index' do
let(:achievement) { instance_double(Achievement) }
before do
allow(Achievement).to receive(:get_public_achievements) { [achievement] }
end
it 'assigns public achievements to template' do
get :index
expect(assigns(achievement)).to eq([achievement])
end
end
end
The index action in the controller
def index
#achievements = Achievement.get_public_achievements
end
The get_public_achievements in the achievement model
def self.get_public_achievements
// empty method it's fine
end
The error:
1) AchievementsController guest user GET index assigns public achievements to template
Failure/Error: expect(assigns(achievement)).to eq([achievement])
expected: [#<InstanceDouble(Achievement) (anonymous)>]
got: nil
(compared using ==)
assigns is keyed by symbols. Should be
expect(assigns(:achievements)).to eq([achievement])
Related
I am writing a controller spec to verify this private method and I get the error Module::DelegationError: ActionController::RackDelegation but I am lost as how to fix this. The best example I have found has been http://owowthathurts.blogspot.com/2013/08/rspec-response-delegation-error-fix.html.
How can I get the unverified spec to pass? I want to make sure the 401 is returned.
Method
def validate_api_request
return four_oh_one unless api_request_verified?(request)
end
Current Spec
describe Api::ApiController, type: :controller do
describe '#validate_api_request' do
it 'verified' do
allow_any_instance_of(described_class).to receive(:api_request_verified?).and_return(true)
expect(subject.send(:validate_api_request)).to be_nil
end
it 'unverified' do
allow_any_instance_of(described_class).to receive(:api_request_verified?).and_return(false)
allow(controller).to receive(:redirect_to)
binding.pry
end
end
end
I'm using Rails 4.
If anyone is working on a similar issue writing controller specs, here is how I solved this based on these 2 guides: http://codegur.com/22603728/test-user-authentication-with-rspec and https://gayleforce.wordpress.com/2012/12/01/testing-rails-before_filter-method/.
describe Api::ApiController, type: :controller do
describe '#validate_api_request' do
controller(Api::ApiController) do
before_filter :validate_api_request
def fake
render text: 'TESTME'
end
end
before do
routes.draw { get 'fake', to: 'api/api#fake' }
end
it 'verified' do
allow_any_instance_of(described_class).to receive(:api_request_verified?).and_return(true)
expect(subject.send(:validate_api_request)).to be_nil
end
it 'unverified' do
allow_any_instance_of(described_class).to receive(:api_request_verified?).and_return(false)
get 'fake'
expect(response.status).to be(401)
end
end
end
Having some problems testing a message broker with rspec given. cant seem to figure out why im receiving this error.
Failure/Error: Given(:profile){ Broker.profile }
ActiveRecord::RecordNotFound:
Couldn't find Profile
But when using pry i have no problems, here is the code.
def profile
#profile ||= begin
Profile.find_by_name!(name)
end
end
test with rspec given
describe '.profile' do
context 'checks for instance variable or finds by name' do
Given(:profile){ Broker.profile }
Then { expect(profile).to be_kind_of (Profile) }
Then { expect(profile.name).to eq Broker.name }
end
end
When doing functional tests for controllers in rails how can I provide dynamic application instance variables to my test which live in the request.
I have a #station object that is initialized in a before action in my application controller (available in all other controllers), however the #station object is defined by the domain entry of the user e.g.: blue.mydomain.com. So it could have 3 different flavors, and the controller actions params[:id] are only valid for a certain flavor.
Further if I don't give my #station a flavor for my test environment it will fail utterly:
(Here code from a helper that gets called in a before action in my application_controller.rb)
def init_station
if Rails.env == "test"
#station=Station.new('blue')
else
#station=Station.new(domain_flavor_picker)
end
end
ApplicationController
....
before_action :init_station
.....
end
Thus I can only test for 'blue' or switch the flavor in my before action and then mock for different id!
test:
describe MyController do
before do
#id="10215d8da3f4f278cec747f09985b5528ec9e"
end
it "should get index action" do
p assigns(:station) # is nil
get :artist_biography, id: #id, locale: I18n.available_locales.sample
assert_response :success
assert_not_nil assigns(:meta)
assert_not_nil assigns(:nav)
assert_not_nil assigns(:content)
end
end
As you can see I am also in need of providing a locale variable. I managed to mix up that call with I18n.available_locales.sample
How can I dynamically switch or manipulate my #station instance variable?
My issue was that I needed to provide minitest with an initial host! From #smathy answer I knew that I needed a Mock Request for the Controller!
Turns out that it is quite easy to set it in MiniTest if you know how!
Rails provides an ActionDispatch::TestRequest object which in itself seems to be a Rack::MockRequest object:
DEFAULT_ENV = Rack::MockRequest.env_for('/', 'HTTP_HOST' => 'test.host', 'REMOTE_ADDR' => '0.0.0.0', 'HTTP_USER_AGENT' => 'Rails Testing' )
So all I had to do in my test was:
before do
#request.env['HTTP_HOST'] = %w(blue.mydomain.com red.mydomain.com green.mydomain.com).sample
end
to initialize my #station object with a sample of flavored domains.
assigns :station will only return a value after you do the request, ie. after the get line. Until you've done the request none of your controller code has been run for that test.
You also shouldn't use #vars in rspec, use let instead, and a few other things that I've shown below, many of which I learned from BetterSpecs
The Crux of your Issue
Assuming that domain_flavor_picker is a method in your controller then you should just mock that so you can different tests for the different return values of it. So, this shows the context for one of the return values of domain_flavor_picker, but you'd add other contexts for other values:
describe MyController do
let(:id) { "10215d8da3f4f278cec747f09985b5528ec9e" }
describe "GET /artist_biography" do
context "when domain_flavor is blue" do
before do
allow(controller).to receive(:domain_flavor_picker) { "blue" } # <-- MOCK!
end
context "when valid id" do
before { get :artist_biography, id: id, locale: I18n.available_locales.sample }
subject { response }
it { is_expected.to be_success }
it "should assign :meta" do
expect(assigns :meta).to be_present # better to have an actual matcher here
end
it "should assign :nav" do
expect(assigns :nav).to be_present # ditto
end
it "should assign :content" do
expect(assigns :content).to be_present # ditto
end
end
end
end
end
Having trouble testing variable values from a controller using RSpec.
Relevant controller code:
class ToysController < ApplicationController
def claim
toy = Toy.find(params[:toy_id])
current_user.toys << toy
toy.status = "claimed"
render :index
end
end
This definitely works -- I know because I puts toy.inspect after it happens, and it's fine. But I can't test it. Here's what my current test looks like, after a lot of messy attempts:
require 'spec_helper'
describe ToysController do
describe "GET 'claim'" do
let(:james) {create(:user)}
let(:toy) {create(:toy)}
before do
OmniAuth.config.mock_auth[:google] = {
uid: james.uid
}
session[:user_id] = james.id
end
it "can be claimed by a user" do
get :claim, toy_id: toy.id
assigns(:toy).user.should eq james.id
end
end
end
When I run the test, I get all sorts of errors on assigns(:toy).user.should indicating that toy is Nil. I've tried messing with the assigns syntax in lots of ways, because I was unable to find the docs for it.
What am I doing wrong? What's the right way to see what the controller does with the user and the toy passed to it?
Edit: Trying to phase over to instance variables, but it still doesn't do the trick. Here's my code again with instance variables (different var names, same results):
Ideas controller:
def claim
#idea = Idea.find(params[:idea_id])
current_user.ideas << #idea
#idea.status = "claimed"
render :index
end
Test:
describe "GET 'claim'" do
let(:james) {create(:user)}
let(:si_title) {create(:idea)}
before do
OmniAuth.config.mock_auth[:google] = {
uid: james.uid
}
session[:user_id] = james.id
end
it "can be claimed by a user" do
get :claim, idea_id: si_title.id
puts assigns(si_title).inspect
end
end
Output: nil.
Solved! Test now reads like this:
describe "GET #claim" do
let(:james) {create(:user)}
let(:si_title) {create(:idea)}
before do
OmniAuth.config.mock_auth[:google] = {
uid: james.uid
}
session[:user_id] = james.id
end
it "can be claimed by a user" do
get :claim, idea_id: si_title.id
assigns(:idea).user_id.should eq james.id
end
end
My mistakes:
Not using a colon to prefix the instance variable name in the assigns.
Using the incorrect variable name in the assigns.
Try replacing toy variable in Controller with #toy. assigns has access only to instance variables.
Using Rspec with Factory Girl. Trying to check out what data is being assigned in my controller (and test against it). Every post I've read says I should be able to get something out of assigns() but it keeps returning nill
Controller
def index
#stickies = Sticky.where(:user_id => current_user.id)
end
Spec
it "should assign stickies" do
foo = assigns(:stickies)
puts "foo = #{foo}"
end
Output
foo =
Am I using the wrong syntax? Is there a better way to do this? Thanks!!
You have to invoke the action first
describe StickiesController do
describe "GET index" do
it "should assign stickies" do
get :index
assigns(:stickies).should_not be_nil
end
end
end
If you are using the rspec > 2.99 you can use:
expect(assigns(:stickies)).not_to be_nil