rspec controller testing after create action has completed - ruby-on-rails

I'm having trouble testing this code in rspec - based on the error the test gives me, I know the test is written (more or less) correctly - as the data it's expecting is correct, it's just not getting it for some reason. I should also note that the code works in the browser.
edit: apologies if this was unclear. In this controller (evaluations_controller), the user iterates through each student in a given group and evaluates their progress against a set of goals. In the new action, #student = groups.student.first - when evaluation data for that student has been saved successfully in the create action, the student_id incremented by 1, and the new student_id is passed to the new action again (so the next student can be evaluated) - this loops until there are no more students.
What I'm trying to test is that the student_id is being successfully incremented after evaluation has been saved in the create action.
Code:
def create
...
if #evaluation.save
#id = params[:student_id]
#id = #id.to_i + 1
redirect_to evaluate_path({ student_group_id: #student_group, student_id: #id})
else
...
end
end
Rspec test:
it "should load the next student" do
#set #id to current student.id +1
#id = #student.id
#id = #id.to_i + 1
#post :create
post :create, {student_group_id: #student_group, student_id: #student, evaluation: #attr}
controller.params[:student_id].should eql #id
end
Error:
Failure/Error: controller.params[:student_id].should eql #id expected: 2 got: "1"

Your code appears to be flawed, and consequently your test is not clear.
From gleaning over the code, I understand you want to use some type of next/previous student functionality. It appears you are hacking around your controller test to achieve that.
if #evaluation.save
#id = params[:student_id]
#id = #id.to_i + 1
You are manually calculating the next id. Ask yourself this: What happens if you are working with student.id 1, and you run this calculation, but student.id 2 has been deleted?
You get an ActiveRecord error.
You need a better way of pulling the next student. You should add an instance method to your Student model to handle that for you:
def next
Student.where(id: id).order("id ASC").first
end
In your controller you can move to the next student as such:
redirect_to evaluate_path({ student_group_id: #student_group, student_id: #student.next.id})
Then your test should be much simpler.

Related

Fixture reverts value after controller method

My app for teachers includes a method to delete a student from a seminar (a class but I didn't want to use the word "class") by deleting that student's record from the join table. I don't delete the student directly, but I delete an "Aula," which is a record in the student/seminar join table. I'm trying to write a test to ensure that when a student is deleted, that student's id is also deleted from the seating chart array. This function appears to be working correctly in development, but not in testing.
The Test
test "Remove student from class period and seating chart" do
log_in_as(#teacher_user)
get seminar_path(#seminar)
seating = [#student.id, #other_student.id]
#seminar.update(:seating => seating)
assert_difference ['Aula.count','#student.aulas.count', '#seminar.students.count'], -1 do
delete aula_path(#aula)
end
puts "In test"
puts #seminar.seating
assert_redirected_to scoresheet_url(#seminar)
end
The Destroy Method in the Aula Controller
def destroy
thisAula = Aula.find(params[:id])
#seminar = Seminar.find(thisAula.seminar_id)
#Remove student from seating chart
seating = #seminar.seating
seating.delete(thisAula.student_id)
#seminar.update(:seating => seating)
puts "In Controller"
puts #seminar.seating
thisAula.destroy
#Redirect
flash[:success] = "Student removed from class period"
redirect_to scoresheet_url(#seminar)
end
Once I fix this error, I would like to include the seating chart count within the test, like so:
assert_difference ['Aula.count','#student.aulas.count', '#seminar.students.count', '#seminar.seating.count'], -1 do
But the test fails there, because the seating array is not decreasing its count.
I've tried those "puts" lines to figure out what is happening.
Thank you in advance for any insight.
-Jeff
Running the test puts:
In Controller
614857506
In Test
45061424
614857506
This shows that the student's id is deleted from the seating array like it should be. But when the program returns to the test, the seating array has reverted to its original form, which includes the id of the deleted student.
Got it. It was a case of needing to reload the model.
#seminar.reload

Agile Web Development with Rails 4 - Iteration E3 Unit Tests

I'm new to Ruby on Rails and reading the book "Agile Web Development with Rails 4". As doing the "Playtime" exercises at the end of chapter 10 (Iteration E3 - Finishing the Cart), I stumbled across some problems.
One of it is in the 2nd exercise, where one should create unit tests to add unique and duplicate products to some shopping cart.
When one adds a product to that cart, it might be the first product of that kind and so the amount is one, but every additional add-operation increases the quantity. This works fine in browser-testing, but my test-cases fail.
Testcase:
test 'duplicates must not be saved as a new line item' do
# create cart and add one product
cart = new_cart_with_one_product(:ruby)
assert cart.save
assert_equal 1, cart.line_items.count
assert_equal 1, cart.line_items.find_by(
product_id: products(:ruby).id).quantity
assert_equal 49.50, cart.total_price.to_f
# ----------------------------------------------------------------
# create a second (actually the same product) and add it to cart:
item = products(:ruby)
cart.add_product(item.id, item.price)
assert cart.save
assert_equal 1, cart.line_items.count, 'duplicate saved as new line'
# test FAILS at the next two lines:
assert_equal 2, cart.line_items.find_by(product_id: item.id).quantity,
'quantity has not been increased'
assert_equal 99.00, cart.total_price.to_f, 'total price is wrong'
end
It tells me that the expected value is 2, but the actual value is 1.
So the quantity has not been increased. The total price does not change either, though both things work in the development-environment.
Here is the code of the Cart-Model:
class Cart < ActiveRecord::Base
has_many:line_items, dependent: :destroy
def add_product(product_id, product_price)
current_item = line_items.find_by(product_id: product_id)
if current_item
current_item.quantity +=1
else
# create a new line_item
current_item = line_items.build(product_id: product_id,
price: product_price)
end
current_item
end
def total_price
line_items.to_a.sum {|item| item.total_price }
end
end
I am using Rails 4.2.5 on Ruby 2.2.3.
I hope somebody can help me with that, because I do not understand why this is happening in the test-environment and using rake test only. If you need any additional code, please let me know.
I finally found my mistake:
The quantity is incremented in the model, for sure, but it isn't saved there.
It is saved in the controller, so this step is totally bypassed in my test because it just tests the model itself.
To fix the test, I changed cart.add_product(item.id, item.price)to cart.add_product(item.id, item.price).save to fix that issue.
I also reloaded the cart before testing, because otherwise it calculates the old total price (thanks to #PrakashMurthy though it should solve another issue, but at the end it helped :-) ).
The (working) Testcase looks like this, now:
test 'duplicates must not be saved as a new line item' do
# create cart and add one product
cart = new_cart_with_one_product(:ruby)
assert cart.save
assert_equal 1, cart.line_items.count
assert_equal 1, cart.line_items.find_by(
product_id: products(:ruby).id).quantity
assert_equal 49.50, cart.total_price.to_f
# ----------------------------------------------------------------
# create a second (actually the same product) and add it to cart:
item = products(:ruby)
# the following two lines do the trick:
cart.add_product(item.id, item.price).save
cart.reload
assert cart.save
assert_equal 1, cart.line_items.count, 'duplicate saved as new line'
assert_equal 2, cart.line_items.find_by(product_id: item.id).quantity,
'quantity has not been increased'
assert_equal 99.00, cart.total_price.to_f, 'total price is wrong'
end

Take random ids, then store those random ids into the db

so I'm working on a code snippet that essentially takes out 35 random ids from the table List.
What I would like to do to find the ids that got randomly generated, store them into a database called Status.
The purpose is to avoid duplication the next time I get a new 35 random ids from the List. So I never get the same random id twice.
Here's what I've tried, but been unsuccessful to get working.
#schedule = current_user.schedules.new
if #schedule.save
#user = User.find(params[:id])
Resque.enqueue(ScheduleTweets, #user.token)
#schedule.update_attribute(:trial, true)
flash[:notice] = "success"
redirect_to :back
else
flash[:alert] = "Try again."
redirect_to :back
end
and the worker:
def self.perform(user_token)
list = List.first(6)
#status = list.statuses.create
list.each do |list|
Status.create(list_id: "#{list}")
if list.avatar.present?
client.create_update(body: {text: "#{list.text}", profile_ids: profile_ids, media: { 'thumbnail' => 'http://png-1.findicons.com/files/icons/85/kids/128/thumbnail.png', 'photo' => 'http://png-1.findicons.com/files/icons/85/kids/128/thumbnail.png' } })
end
end
end
however the Status.create(list_id: #list) doesn't work.
Does anybody have any idea what is going on, and how I can make the list_ids get saved successfully to Status?
It's also associated:
list has many statuses, and status belongs to list
The following line of code is wrong:
Status.create(list_id: "#{list}") # WRONG
In your case the list variable is a List instance. And you're passing its string version to list_id which expects an integer.
Do this:
Status.create(list_id: list.id)
Or this:
list.statuses.create
I think the following will also work:
Status.create(list: list)

assigning values to model

I'm kinda new to coding on rails. It would be great if you could help me out with what I think might be noob question.Here's my code:
def create
#project = Project.new(params[:project])
if #project.save
redirect_to new_project_path
end
student=#project.student_str.split(";")
#users = User.where(:code => student)
#users.each do |c|
puts c.email
end
#users.each do |c|
puts "I'm here"
c.projects = "#{c.projects};#{#project.id}"
end
end
So, in the create method, Each time a new project is created a string called student_str is stored where the ID number of each student is seperated by a ";". I split that string to an array using the split function to get an array of student ID's. I have the puts c.email and puts "I'm here" to make sure the loops are working fine. I get the proper outputs on terminal.
The problem here is the
c.projects = "#{c.projects};#{#project.id}"
That simply does not seem to be working.
My model is not updated when this line is executed. I get no errors though.
Can you tell me what I might have to do to fix this?
thanks!
You have to call c.save after you updated the projects attribute. Otherwise the object is updated but not the database so the next time you load it the changes are gone.

Rails validations running against original record during update

I'm trying to figure out an inconsistency between what's happening in a functional test and what is happening in my development environment. I have a custom validation method unique_entry that is essentially a specialized version of validates_uniqueness_of. It looks like this:
def unique_entry
matched_entry = Entry.first(:conditions => ['LOWER(field_one) = LOWER(?) AND LOWER(field_two) = LOWER(?)', self.field_one, self.field_two])
errors.add_to_base('Duplicate detected') if matched_entry && (matched_entry.id != self.id)
end
The update action in the controller is very basic:
def update
if #entry.update_attributes(params[:entry])
flash.now[:success] = 'Success'
render :action => 'show'
else
flash.now[:error] = 'Error'
render :action => 'edit'
end
end
This works just fine when I'm creating a new record. When I update a record, however, I get inconsistent behavior. If I test it from a browser in my development environment, it correctly renders the edit action with an error message, but in my functional test, it accepts the update as successful. Here is the test:
test "should not update entry and should render edit view if invalid update" do
put :update, { :id => 1, :field_one => 'new_value', :field_two => 'new_value' } # 'new values' are the same as another existing record to trigger the duplication check
assert_template :edit
assert_not_nil flash[:error]
end
I looked at the test log and discovered that the values unique_entry is using are the record's original values instead of the values it should be attempting to update with. That is, the first line of unique_entry generates an SQL query like this:
SELECT * FROM "entries" WHERE (LOWER(field_one) = LOWER('original_value_of_field_one') AND LOWER(field_two) = LOWER('original_value_of_field_two')) LIMIT 1
What am I missing here? Why do my validations seem to be running against the original record instead of the new values only in the test environment?
In your test, shouldn't there be some reference to :entry, since that is what you are looking for in the controller params[:entry] ?

Resources