how do I test controller method using rspec? - ruby-on-rails

I'm trying to learn rspec. I can't seem to test a rails controller method. When I call the method in the test, rspec just returns an undefined method error. Here is my test example
it 'should return 99 if large' do
GamesController.testme(1000).should == 99
end
and here is the error:
Failure/Error: GamesController.testme(1000).should == 99
NoMethodError:
undefined method `testme' for GamesController:Class
I do have a testme method in the GamesController. I don't understand why the test code cannot see my methods.
Any help is appreciated.

I think the correct way is this:
describe GamesController do
it 'should return 99 if large' do
controller.testme(1000).should == 99
end
end
In a rails controller spec, when you put the controller class in describe, you can use controller method to get an instance :P
Obviously, if testme method is private, you still have to use controller.send :testme

You try to test class method, but controller has instance method
You need GamesController.new.testme(1000).should == 99
Or even GamesController.new.send(:testme, 1000).should == 99, because, as I think, this is not action method, but private or protected.
Action methods are tested this way

Related

Rspec test with mock for a static method and non static method

I have a method like this:
def self.method
#API CALL
end
And I was writing a test for the controller method that calls this static method. It is like this:
it 'update order to confirmed' do
Order.should_receive(:process_payment).and_return({})
sign_in user
attributes = FactoryGirl.attributes_for(:order, :valid_order)
patch :confirm_order, params: { id: order.id, order: attributes }
order.reload
expect(order.confirmed).to eq true
end
And it was working fine. But I had to make this method not static, and the test starts to fail.
In my controller, I am calling the method like this now:
Order.new.process_payment(#order)
The problem is with my mock I guess, but I cannot see how to solve it. Any ideas on how I can adapt my mock to this new format?
You can use allow_any_instance_of method:
allow_any_instance_of(Order).to receive(:process_payment).and_return({})
Igor's answer works fine. I've also managed to make it work like this:
Order.any_instance.should_receive(:process_payment).and_return({})

RSpec3 and message expectations

I'm using rspec 3.0.3 and ruby 2.1.2 and just can't figure out what's going wrong.
Sorry for not good code implementation (I mean that class variables), but it was the easier way to show whats going wrong.
I have 2 classes. First calling new_method of the Test class should call AnotherTest.call_method that should change ##c_var class variable.
require "rspec"
class Test
def self.new_method
AnotherTest.call_method
end
end
class AnotherTest
##c_var = "hola"
def self.call_method
##c_var = "holla from another test"
end
def self.c_var
##c_var
end
end
And I'm writing specs for it:
describe Test do
it "should call method from an other class" do
Test.new_method
expect(AnotherTest.c_var).to be_eql("holla from another test")
end
end
And this specs is working OK. But then I'm trying to use "expect to receive call" something goes wrong
describe Test do
it "should call method from an other class" do
expect(AnotherTest).to receive(:call_method).and_return("holla from another test")
Test.new_method
expect(AnotherTest.c_var).to be_eql("holla from another test")
end
end
Failures:
1) Test should call method from an other class
Failure/Error: expect(AnotherTest.c_var).to be_eql("holla from another test")
expected `"hola".eql?("holla from another test")` to return true, got false
# ./test.rb:26:in `block (2 levels) in <top (required)>'
Seems like RSpec is making this check in something like a migration and doing a rollback after it.
It's such a strange sample, I know, but I've noticed this bug only then method of one instance of a class is calling method from the other instance and that method is trying to change something.
By using expect(...).to receive(...), the original method is not being called. Rather, when it is called, it just returns whatever you passed into and_return(...) without actually executing your method.
What you probably want is and_call_original. This way, you can ensure the method is called, and still allow it to execute:
expect(AnotherTest).to receive(:call_method).and_call_original
Source: https://www.relishapp.com/rspec/rspec-mocks/v/3-0/docs/configuring-responses/calling-the-original-implementation

Rspec controller test - how to pass arguments to a method I'm testing

I want to test this method in my controller.
def fetch_match_displayed_count(params)
match_count = 0
params.each do |param|
match_count += 1 if param[1]["result"] && param[1]["result"] != "result"
end
match_count
end
This is the test I've written so far.
describe "fetch_match_displayed_count" do
it "should assign match_count with correct number of matches" do
params = {"result_1"=>{"match_id"=>"975", "result"=>"not_match"}, "result_2"=>{"match_id"=>"976", "result"=>"match"}, "result_3"=>{"match_id"=>"977", "result"=>"not_sure"}, "result_4"=>{"match_id"=>"978", "result"=>"match"}, "result_5"=>{"match_id"=>"979", "result"=>"not_match"}, "workerId"=>"123", "hitId"=>"", "assignmentId"=>"", "controller"=>"mt_results", "action"=>"create"}
controller.should_receive(:fetch_match_displayed_count).with(params)
get :fetch_match_displayed_count, {params:params}
assigns(:match_count).should == 5
end
end
My problem seems to lie in this line get :fetch_match_displayed_count, {params:params}
The method is expecting params, but is getting nil.
I have two questions.
Should this method be in a helper and not in the controller itself (per Rails convention)?
How do I submit a get request and pass params in my test?
As a general rule, you should test the public interface of your class. For a controller, this means you test actions, not helper methods.
You should be able to make this work by setting up one or more separate test cases that call the appropriate action(s), then use a message expectation to test that the helper method is called with the right arguments -- or test that the helper method does what it is supposed to do (sets the right instance variables/redirects/etc).

Understanding Rspec Stubs and Controller Tests

My first time I'm using a stub and I have a controller that runs a method when the page is called. If that method returns empty I want a redirect back to the home page. Thus my controller looks like this
def jobs
if scrap_cl().empty?
redirect_to home_path
flash[:error] = "Nothing found this month!"
end
end
For my test, I want to test the redirect when that method returns empty. So far I have this
context "jobs redirects to homepage when nothing returned from crawlers" do
before do
PagesController.stub(:scrap_cl).and_return("")
get :jobs
end
it { should respond_with(:success) }
it { should render_template(:home) }
it { should set_the_flash.to("Nothing found this month!")}
end
When I run rpsec I get the two errors, one on rendering the template and the other on flash. Thus, it's sending me to to the jobs page. What am I doing wrong with the stub and test?
Your stub there is going to stub out a class method called scrap_cl, which will never be called. You want the instance method. You can get to this easily with RSpec's any_instance:
PagesController.any_instance.stub(:scrap_cl).and_return("")
This will cause all instances of PagesController to stub that method, which is what you actually want here.

Rspec: how can I check if a call to a method of another class is called?

I can I check if FeedItem::populate_from_friend_to_user is called inside the user class?
it "should auto populate feed after user.add_friend" do
#user.add_friend(#friend1)
#user.should_receive('FeedItem::populate_from_friend_to_user').with(#friend1, #user)
end
With the above code I get:
undefined method `populate_from_friend_to_user' for :FeedItem:Symbol
You should not know where the method is called, just if the method is called.. You just know if the method is call:
Before RSpec 3
it "should auto populate feed after user.add_friend" do
FeedItem.should_receive(:populate_from_friend_to_user).with(#friend1, #user)
#user.add_friend(#friend1)
end
In RSpec 3 the syntax is
expect(Object).to receive(:method).with(params)
Remember that is works only in rspec2 . For rspec3 u call
expect(#user).to receive(:your_method)
https://www.relishapp.com/rspec/rspec-mocks/v/3-0/docs/message-expectations

Resources