I've written a model method that checks the validity of a VAT number using the EU's VIES system (How to use SOAP service with xml in Rails (EU VAT number check)). This works in development.
Now I'm trying to write a model test to see if the model method is able to get a response from that system:
test "test check_valid" do
#organization.number = "TESTVATNUMBER" # In def setup, #organization receives all the other relevant variables
#organization.save
#organization.check_vat # Calls upon the model method
assert ??? # How to test that the previous line/method has indeed returned the value 'false' to the controller?
end
How to complete this test? That is, how to test that check_vat worked correctly and returned the value 'false' to the controller method?
These attempts below produced the error undefined method 'assert_response' for #<OrganizationTest:0x00000007686918>:
#organization.check_validity_vat_nr
assert_response :success
assert_response 'false' do
#organization.check_validity_vat_nr
end
Related
I'm writing a pretty straightforward method. Whenever a referer has referred 5 people to become new users, I want them to get a refund. This means that when a new user is created, there's a method check_referer that checks to see if the person who referred them (if this person exists) should get a refund because they've now referred 5 people in total.
In the test logs, based on the puts statement, I can tell that the code is working and the refund_membership_fees_paid method is indeed being called once. But the test keeps failing with:
Failure/Error: #referer.should_receive(:refund_membership_fees_paid).exactly(1).times
(#<User:0x007fbf46bf1c58>).refund_membership_fees_paid(any args)
expected: 1 time with any arguments
received: 0 times with any arguments
Test code:
describe User, "Test refund_membership_fees_paid method is called" do
before do
#referer = User.new()
#referer.save(validate:false)
RefererRefundAlert.stub_chain(:new, :async, :perform)
end
it "at 5 users" do
5.times do |index|
u = User.new(referred_by: #referer.id)
u.save(validate:false)
end
#referer.should_receive(:refund_membership_fees_paid).exactly(1).times
end
end
Model code:
def check_referer
if self.referred_by.present? && User.where(referred_by: self.referred_by).count == 5
User.find(self.referred_by).refund_membership_fees_paid
end
end
def refund_membership_fees_paid
puts "refund_membership_fees_paid method"
RefererRefundAlert.new.async.perform(self.id)
end
User.find does not return the same object as #referer; it will return a different instance of User that represents the same user in the database.
Instead of checking whether refund_membership_fees_paid is called, you can verify that the correct user ID is getting passed intoRefererRefundAlert.new.async.perform.
Also, as others mentioned, you should set your expectation before running the tested methods.
RefererRefundAlert.new.async.should_receive(:perform)
.with(#referer.id).exactly(1).times
5.times do |index|
u = User.new(referred_by: #referer.id)
u.save(validate:false)
end
The use of should_receive is to set the expectation for the following action.
For example, if your account.close action is supposed to log the closure, the test would be...
logger.should_receive(:account_closed)
account.close
So your example should be restructured to put the test first...
#referer.should_receive(:refund_membership_fees_paid).exactly(1).times
5.times {User.new(referred_by: #referer.id).save(validate: false)}
I am new to ruby on rails. I am getting an undefined method error when I run rspec on comment_spec.rb
1) after_save calls 'Post#update_rank' after save
Failure/Error: request.env["HTTP_REFERER"] = '/'
NameError:
undefined local variable or method `request' for #<RSpec::ExampleGroups::AfterSave:0x007fa866ead8d0>
# ./spec/models/vote_spec.rb:45:in `block (2 levels) in <top (required)>'
This is my spec:
require 'rails_helper'
describe Vote do
....
describe 'after_save' do
it "calls 'Post#update_rank' after save" do
request.env["HTTP_REFERER"] = '/'
#user = create(:user)
#post = create(:post, user: #user)
sign_in #user
vote = Vote.new(value:1, post: post)
expect(post). to receive(:update_rank)
vote.save
end
end
Any help that you would have would be greatly appreciated...
I was following the apirails book tutorial chapter 3 here
http://apionrails.icalialabs.com/book/chapter_three
I was receiving the same error and DrPositron's solution worked for me, all green again. Just needed to add ":type => :controller" on my block like so:
describe Api::V1::UsersController, :type => :controller do
end
Hope this helps someone
OK here's the deal.
Vote is a model, i suppose.
You are writing a test for that model.
There's a difference between model tests ("the domain logic is doing what its supposed to") and feature/integration tests ("the application is behaving the way its supposed to").
The request variable is associated with feature or controller tests.
So what's wrong?
You are not logging in users in model tests, just check if the update_rank method is being called on save, thats it.
No user-interaction jazz in model tests.
Hope that helps!
Cheers
Jan
So Louis, just to expand on Jan's response:
You appear to be writing a model spec. The purpose of a model spec is simply to test how your model classes work, and that behavior is testable without having to pay any attention to the application logic around signing in, making "requests" to particular controllers, or visiting particular pages.
You're essentially just testing a couple related Ruby classes. For this, we don't need to think about the whole app -- just the classes we're testing.
As a consequence, RSpec doesn't make certain methods available in the spec/models directory -- you're not supposed to think about requests or authentication in these tests.
It looks like your test is simply designed to make sure that when you create a vote for a post, it updates that post's rank (or, specifically, call's that post's update_rank method). To do that, you don't need to create a user, or sign a user in, or pay any attention to the request (what request would we be referring to? We're just testing this as if in Rails console, with no HTTP request involved).
So you could basically remove the first four lines of your test -- apart from the line creating your post, and the post's user if it's necessary (if the post model validates the presence of a user). Don't sign a user in -- we're just testing a Ruby class. There's no concept of a website to sign into in this test.
Then, as a last thing to take care of to get your spec to pass, make sure to refer to the post you create by the right name. Right now, you're creating a post and assigning it to the #post variable, but then you're referring to just post later on. post doesn't exist; just #post. You'll have to pick one variable name and stick with it.
Also, if you are using RSpec 3, file type inference is now disabled by default and must be opted in as described here. If you're new to RSpec, a quick overview of the canonical directory structure is here.
For example, for a controller spec for RelationshipsController, insert , :type => :controller as such:
describe RelationshipsController, :type => :controller do
#spec
end
When i run test cases, i don't want to store records in my databases. How can i achieve it.
Here is my code :-
class Sample << Test::Unit::TestCase
def setup
# code
end
def teardown
# code
end
def test_sample
# code
end
end
Am using the following gem:-
gem 'test-unit'
to run tests and api call for GET/POST/PUT/DELETE methods to create/delete records in database.
I assume what you mean is that the objects you are using are not persisted in a local database, but rather in a remote system accessed via an API. That is, when you save an objects attributes, they are sent to a remote server via an API call.
Have a look at webmock. It works well with test/unit and test/minitest (which is test/unit on steroids). Basically you define the http call that should result from an action, and pass that to webmock. Then when the action is tested webmock will intercept the http call, and return a mocked response. If the action call is different to the one you defined, web mock will generate an error that will cause the test to fail.
So say on creating a sample, you expect a POST to example.com/samples with a sample attribute :foo set to 'bar', you could write a test like this:
def test_create_sample
data = 'bar'
sample = Sample.new
sample.foo = data
stub_request(:post, "example.com/samples/1").
with(:body => {:sample => {foo: data}})
assert sample.save
end
This also assumes that your save action checks the api response, and returns true if everything is OK.
I am trying to test a controller method with the following code:
it "should set an approved_at date and email the campaign's client" do
#campaign = Campaign.create(valid_attributes)
post :approve, id: #campaign.id.to_s
#campaign.reload
#campaign.approved_at.should_not be(nil)
end
However, when I run this test, I get the following error:
Failure/Error: #campaign.reload
ActiveRecord::RecordNotFound:
Couldn't find Campaign without an ID
When I run the analagous lines in the rails console, the reload works and the value is set as I need it to be. Why isn't reload working for me when I run the code in an rspec test?
I solved the problem by switching to FactoryGirl:
#campaign = FactoryGirl.create(:pending_approval_campaign)
#campaign.approved_at.should be(nil)
post :approve, id: #campaign.id.to_s
#campaign.reload
#campaign.approved_at.should_not be(nil)
That works as intended
Two possible places for errors.
object creation. i.e.#campaign = Campaign.create(valid_attributes) Your object may not be created correctly. I suggest you to use create! instead of create in the test so that any error will be thrown.
Controller. When controller expect to find the object with an integer id, you feed it a string. That may also be the problem. I suggest you not to convert the id into string. If for GET, you can do that though not necessary. If for POST, converting to string is wrong.
I would run a test to ensure a Campaign record is actually being created:
#campaign = Campaign.create(valid_attributes)
puts #campaign.id
.reload is the first place in your code that a nil #campaign would flag an error (since you can call .to_s on a nil object)
The following generates an error: "undefined local variable or method `params'"
assert_equal params[:recipient_id], users(:one).id
How do you test the params hash?
Also, how do you test assert_redirect when there are params present? The params are appended to the URL, so testing for model_path or similar fails.
Working with built in test class in Rails 3.
http://guides.rubyonrails.org/testing.html#functional-tests-for-your-controllers gives some of this information.
In this case, params is attached to the #request or #response object (depending on what HTTP method you are testing), so you can refer to it as #request.params[:recipient_id].
For redirect:
assert_redirected_to post_path(assigns(:post)) will assert that you are redirected to the proper path for a given model. The assigns method should have the instance variables you are setting inside of the controller to pass to the view