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
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
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.
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.
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.
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.