How to test if other models were created correctly - ruby-on-rails

I have a Account.create! method that creates multiple other models.
In my RSpec test how can I test if the other models were created correctly?
it "should create an account" do
params = ....
Account.create!(params)
expect(account.valid?).to eq(true)
end
My Account.create! method looks like:
def self.create!(params)
account = Account.new(params)
user = ...
user.save!
location = ...
location.save!
account
end

For one thing, you can test that the records were created at all.
it "should create a user" do
params = ....
expect(Account.create!(params)).to change{User.count}.by(1)
end
Also, you can use User.last to retrieve the last user created and check the attributes are what you would want to see.

Related

Rails - Object creation for rspec whose class is defined lib/classes

I am trying to write Rspec test case for the submit method in the app/controllers.sample.rb file.
User class is defined in the lib/classes folder. User object is created in the session.rb file in app/controllers/concerns which is autoloaded during creation of new session.
The user method in the session.rb gets the user parameters from another API.
Here I am finding it difficult to create the User object using Rspec, it is always returning error at
list = user.get_list
I have given the sample set of code I have written for the test case.
Could anyone help how to instantiate the User object in concerns/session.rb from rspec ?
app/controllers/concerns/session.rb
def user
if user
user
else
begin
rest_resource = RestClient::Resource.new(ENV['SESSION_API'], :verify_ssl => false)
data = rest_resource.get Authorization: request.headers['Authorization']
rescue RestClient::Exception => e
#error = JSON.parse(e.response, symbolize_names: true)
return nil
end
self.user = User.new(current_user,request.headers['Authorization'] )
end
end
spec/controllers/rspec_sample.rb
describe "Submit" do
it "Submit and expects to succeed" do
allow_any_instance_of(Concerns::Session).to receive(:current_user).and_return(name: "test")
allow_any_instance_of(Concerns::Session).to receive(:user).and_return(name: "test")
post :submit, params
expect(response).to have_http_status(200)
end
end
app/controllers/sample.rb
def submit
list = user.get_list
end
lib/classes/user.rb
class User
def list
return values
end
end

RSpec not recognizing deleted association

In my rails application, a user has many baskets, and a basket belongs to a user. The User class also contains an instance method that removes the user's id from all associated baskets. I am having issues testing that method using RSpec, FactoryGirl and Faker.
class Basket
belongs_to :user, optional: true
end
class User
has_many: baskets
def disassociate_baskets
baskets.each { |b| b.update(user: nil) }
end
end
The disassociate_baskets method works with real data, my RSpec test fails because in the test environment because the basket-user association persists even after running the method. Here's my testing code:
#Basket Factory
FactoryGirl.define do
factory :basket do
date { Faker::Date.backward }
end
end
#User Factory
FactoryGirl.define do
factory :user do
name { Faker::Name.name }
end
end
#user_spec.rb
describe "When deleting purchase history" do
before do
#user = create(:user)
#user1 = create(:user)
#basket = create(:basket, user: #user)
#basket1 = create(:basket, user: #user)
#basket2 = create(:basket, user: #user1)
end
it "disassociates the user from the basket" do
#user.disassociate_baskets
expect(#basket.user).to eq nil
end
end
I've inspected the objects inside the it block, and they are fine, but #basket is still associated to #user even after running disassociate_baskets method, so my test fails. What am I missing here?
Possible solution:
expect(#basket.reload.user).to eq nil
Why you need to reload it:
When you create the new basket and assign it to #basket, it will have an associated User assigned to it. Then, you call #user.disassociate_baskets, which loops over all the baskets of that user by instantiating them one by one, and updating their user attribute.
But since #user.disassociate_baskets instantiated brand new Basket instances, the user attribute will be set to nil only in these new instances. #basket has no idea that another instance got modified, and has to be reloaded manually.

Why must I reload records in rspec after using customer validators?

I've got a model User that has options created in a callback after it is created
# User
has_one :user_options
after_create :create_options
private
def create_options
UserOptions.create(user: self)
end
I have some simple Rspec coverage for this:
describe "new user" do
it "creates user_options after the user is created" do
user = create(:user)
user.user_options.should be_kind_of(UserOptions)
end
end
Everything worked until I added custom validation to the User model.
validate :check_whatever, if: :blah_blah
Now the spec fails and the only way to make it pass is to reload the record in the spec:
it "creates user_preferences for the user" do
user = create(:user)
user.reload
user.user_options.should be_kind_of(UserOptions)
end
What is the reason for this?
First of all I would recommend reading this article about debugging rails applications: http://nofail.de/2013/10/debugging-rails-applications-in-development/
Secondly I would propose some changes to your code:
def create_options
UserOptions.create(user: self)
end
should be
def create_options
self.user_option.create
end
that way you don't have to reload an object after save, because the object already has the new UserOptions entity in it's relation.
Assuming from the code create(:user) you are using fixtures. There might be a problem with the data that you are using the in the user.yml and the validation that you wrote, but unfortunately did not post here.

How to call the create action from the controller in RSpec

I have a controller create action that creates a new blog post, and runs an additional method if the post saves successfully.
I have a separate factory girl file with the params for the post I want to make. FactoryGirl.create calls the ruby create method, not the create action in my controller.
How can I call the create action from the controller in my RSpec? And how would I send it the params in my factory girl factories.rb file?
posts_controller.rb
def create
#post = Post.new(params[:post])
if #post.save
#post.my_special_method
redirect_to root_path
else
redirect_to new_path
end
end
spec/requests/post_pages_spec.rb
it "should successfully run my special method" do
#post = FactoryGirl.create(:post)
#post.user.different_models.count.should == 1
end
post.rb
def my_special_method
user = self.user
special_post = Post.where("group_id IN (?) AND user_id IN (?)", 1, user.id)
if special_post.count == 10
DifferentModel.create(user_id: user.id, foo_id: foobar.id)
end
end
end
Request specs are integration tests, using something like Capybara to visit pages as a user might and perform actions. You wouldn't test a create action from a request spec at all. You'd visit the new item path, fill in the form, hit the Submit button, and then confirm that an object was created. Take a look at the Railscast on request specs for a great example.
If you want to test the create action, use a controller spec. Incorporating FactoryGirl, that would look like this:
it "creates a post" do
post_attributes = FactoryGirl.attributes_for(:post)
post :create, post: post_attributes
response.should redirect_to(root_path)
Post.last.some_attribute.should == post_attributes[:some_attribute]
# more lines like above, or just remove `:id` from
# `Post.last.attributes` and compare the hashes.
end
it "displays new on create failure" do
post :create, post: { some_attribute: "some value that doesn't save" }
response.should redirect_to(new_post_path)
flash[:error].should include("some error message")
end
These are the only tests you really need related to creation. In your specific example, I'd add a third test (again, controller test) to ensure that the appropriate DifferentModel record is created.

How to spec controller where model associations occur

I'm trying to spec the controller code:
# ClustersController
def create
# create new cluster
#cluster.user = current_user
# save code
end
I am using Rails 3 / RSpec 2 and I'm fairly new to the TDD flow. I basically want to make sure that the user attribute is assigned during the create action.
To begin with i don't think you should create, update an save the object. You can pass the user to the create method, like this:
Cluster.create(:user => current_user)
And to test this you can do:
describe ClusterController do
describe "POST create" do
it "creates a new cluster" do
lamda do
post :create
end.should change(Cluster, :count).by(1)
end
it "set the current user as the new cluster's user" do
user = mock()
Cluster.should_receive(:create).with(:user => user)
post :create
assign(:cluster).user.should == user
end
end
end
I think that will do.
Hope that help.

Resources