Testing requests with rspec

huangapple go评论99阅读模式
英文:

Testing requests with rspec

问题

I've translated the code part as requested:

  1. module Api
  2. module V1
  3. class PaymentsController < ApplicationController
  4. before_action :authenticate_user!
  5. before_action :set_payment, only: %i[show edit update destroy]
  6. # GET /payments or /payments.json
  7. def index
  8. if user_signed_in?
  9. @payments = current_user.payments.order(created_at: :desc)
  10. render json: @payments.to_json(include: %i[home user])
  11. else
  12. render json: {}, status: 401
  13. end
  14. end
  15. # GET /payments/1 or /payments/1.json
  16. def show
  17. @payment = current_user.payments.find(params[:id])
  18. render json: @payment.to_json(include: %i[home user])
  19. end
  20. # GET /payments/new
  21. def new
  22. @home = Home.find(params[:home_id])
  23. @payment = @home.payments.new
  24. end
  25. # GET /payments/1/edit
  26. def edit; end
  27. # POST /payments
  28. def create
  29. @home = Home.find(params[:home_id])
  30. @payment = @home.payments.create(payment_params) do |p|
  31. p.user = current_user # if user_signed_in?
  32. end
  33. if @payment.save
  34. render json: @payment.to_json(include: %i[home user])
  35. else
  36. render json: @payment.errors, status: :unprocessable_entity
  37. end
  38. end
  39. # PATCH/PUT /payments/1 or /payments/1.json
  40. def update
  41. @home = Home.find(params[:home_id])
  42. @payment = @home.payments.find(params[:id])
  43. if @payment.update
  44. render json: { notice: 'Payment was successfully updated.' },
  45. status: :ok
  46. else
  47. render json: { error: 'Unable to update payment' },
  48. status: :unprocessable_entity
  49. end
  50. end
  51. # DELETE /payments/1 or /payments/1.json
  52. def destroy
  53. @home = Home.find(params[:home_id])
  54. @payment = @home.payments.find(params[:id])
  55. @payment.destroy
  56. render json: { notice: 'Payment succefully removed' }
  57. end
  58. private
  59. # Use callbacks to share common setup or constraints between actions
  60. def set_payment
  61. @payment = Payment.find(params[:id])
  62. end
  63. # Only allow a list of trusted parameters through.
  64. def payment_params
  65. params.require(:payment).permit(:first_name, :last_name, :phone_number, :address, :money_paid, :date,
  66. :nin_number, :user_id, :home_id)
  67. end
  68. end
  69. end
  70. end

If you need further assistance with this code or have specific questions, feel free to ask.

英文:
  • hey guys, am trying to build tests for my controllers using rspec , I have 3 models and controllers i.e user, payment and home
    -These mode;s are associated in search a way that, payment belongs to user and home, home has many payments, and user has many payments.

-I have managed to write tests for these associations for the models , now am stuck forthe controllers.

  • Below is what i have tried to write
  1. require 'rails_helper'
  2. RSpec.describe 'Payments', type: :request do
  3. let(:valid_attributes) do
  4. { first_name: 'mutebi', last_name: 'godfrey', phone_number: '+256780140670', address: 'kampala', money_paid: '6000', date: '25/08/2023',
  5. nin_number: 'KK45896587450P', user_id: '5', home_id: '9' }
  6. end
  7. let(:invalid_attributes) do
  8. skip('Add a hash of attributes invalid for your model')
  9. end
  10. describe 'GET /index' do
  11. it 'renders a successful response' do
  12. Payment.create! valid_attributes
  13. get payments_url, headers: valid_headers, as: :json
  14. expect(response).to be_successful
  15. end
  16. end
  17. describe 'GET /show' do
  18. it 'renders a successful response' do
  19. payment = Payment.create! valid_attributes
  20. get payment_url(payment), as: :json
  21. expect(response).to be_successful
  22. end
  23. end
  24. end
  • and getting this error below in the console. i think the problem could be with the associations
  1. 1) Payments GET /index renders a successful response
  2. Failure/Error: Payment.create! valid_attributes
  3. ActiveRecord::RecordInvalid:
  4. Validation failed: User must exist, Home must exist
  5. # ./spec/requests/payments_spec.rb:17:in `block (3 levels) in <main>'
  6. 2) Payments GET /show renders a successful response
  7. Failure/Error: payment = Payment.create! valid_attributes
  8. ActiveRecord::RecordInvalid:
  9. Validation failed: User must exist, Home must exist
  10. # ./spec/requests/payments_spec.rb:25:in `block (3 levels) in <main>'
  • Below is my controller which am trying to test
  1. # frozen_string_literal: true
  2. module Api
  3. module V1
  4. class PaymentsController < ApplicationController
  5. before_action :authenticate_user!
  6. before_action :set_payment, only: %i[show edit update destroy]
  7. # GET /payments or /payments.json
  8. def index
  9. if user_signed_in?
  10. @payments = current_user.payments.order(created_at: :desc)
  11. render json: @payments.to_json(include: %i[home user])
  12. else
  13. render json: {}, status: 401
  14. end
  15. end
  16. # GET /payments/1 or /payments/1.json
  17. def show
  18. @payment = current_user.payments.find(params[:id])
  19. render json: @payment.to_json(include: %i[home user])
  20. end
  21. # GET /payments/new
  22. def new
  23. @home = Home.find(params[:home_id])
  24. @payment = @home.payments.new
  25. end
  26. # GET /payments/1/edit
  27. def edit; end
  28. # POST /payments
  29. def create
  30. @home = Home.find(params[:home_id])
  31. @payment = @home.payments.create(payment_params) do |p|
  32. p.user = current_user # if user_signed_in?
  33. end
  34. if @payment.save
  35. render json: @payment.to_json(include: %i[home user])
  36. else
  37. render json: @payment.errors, status: :unprocessable_entity
  38. end
  39. end
  40. # PATCH/PUT /payments/1 or /payments/1.json
  41. def update
  42. @home = Home.find(params[:home_id])
  43. @payment = @home.payments.find(params[:id])
  44. if @payment.update
  45. render json: { notice: 'Payment was successfully updated.' },
  46. status: :ok
  47. else
  48. render json: { error: 'Unable to update payment' },
  49. status: :unprocessable_entity
  50. end
  51. end
  52. # DELETE /payments/1 or /payments/1.json
  53. def destroy
  54. @home = Home.find(params[:home_id])
  55. @payment = @home.payments.find(params[:id])
  56. @payment.destroy
  57. render json: { notice: 'Payment succefully removed' }
  58. end
  59. private
  60. # Use callbacks to share common setup or constraints between actions
  61. def set_payment
  62. @payment = Payment.find(params[:id])
  63. end
  64. # Only allow a list of trusted parameters through.
  65. def payment_params
  66. params.require(:payment).permit(:first_name, :last_name, :phone_number, :address, :money_paid, :date,
  67. :nin_number, :user_id, :home_id)
  68. end
  69. end
  70. end
  71. end

答案1

得分: 0

你似乎没有真正理解工厂是什么以及如何使用它们。工厂应该生成您可以在测试中使用的唯一数据。

因此,要清理您的工厂,您可以使用 ffaker gem 生成伪随机数据,而不是使用您自己的个人数据(不应该这样使用):

  1. FactoryBot.define do
  2. factory :payment do
  3. first_name { FFaker::Name.first_name }
  4. last_name { FFaker::Name.last_name }
  5. phone_number { FFaker::PhoneNumberNL.international_mobile_phone_number }
  6. address { FFaker::Address.street_address }
  7. money_paid { FFaker::Number.decimal }
  8. nin_number { FFaker::Identification.ssn }
  9. user # 不要硬编码 ID!
  10. home # 不要硬编码 ID!
  11. end
  12. end

在测试中使用伪随机数据可以避免您的测试依赖于测试之外的信息。这是您使用工厂而不是固定装置的最重要原因之一。

然后,在测试设置阶段中在您的规格中使用工厂:

  1. require 'rails_helper'
  2. RSpec.describe 'Payments', type: :request do
  3. let(:payment) { FactoryBot.create(:payment) }
  4. describe 'GET /index' do
  5. let!(:payments) { FactoryBot.create_list(:payment, 5) }
  6. it 'renders a successful response' do
  7. get payments_url, headers: valid_headers, as: :json
  8. expect(response).to be_successful
  9. end
  10. end
  11. describe 'GET /show' do
  12. it 'renders a successful response' do
  13. get payment_url(payment), as: :json
  14. expect(response).to be_successful
  15. end
  16. it 'has the correct JSON' do
  17. get payment_url(payment), as: :json
  18. expect(response.parsed_body).to match(a_hash_including(
  19. payment.attributes.slice(
  20. "first_name", "last_name", "address" # ...
  21. )
  22. ))
  23. end
  24. end
  25. end
英文:

You haven't really understood what factories are or how to use them. Factories should generate unique data that you can use in your tests.

So to clean up your factory you could use the ffaker gem to generate psuedo random data instead of your own personal data (which you shouldn't be using like this):

  1. FactoryBot.define do
  2. factory :payment do
  3. first_name { FFaker::Name.first_name }
  4. last_name { FFaker::Name.last_name }
  5. phone_number { FFaker::PhoneNumberNL.international_mobile_phone_number }
  6. address { FFaker::Address.street_address }
  7. money_paid { FFaker::Number.decimal }
  8. nin_number { FFaker::Identification.ssn }
  9. user # DO NOT HARDCODE ID's!
  10. home # DO NOT HARDCODE ID's!
  11. end
  12. end

Using psuedo random data in your tests avoids your tests becoming reliant on information outside the test. This one of the biggest reasons why you would use factories instead of fixtures.

You then use the factory in your specs in the test setup phase:

  1. require 'rails_helper'
  2. RSpec.describe 'Payments', type: :request do
  3. let(:payment) { FactoryBot.create(:payment) }
  4. describe 'GET /index' do
  5. let!(:payments) { FactoryBot.create_list(:payment, 5) }
  6. it 'renders a successful response' do
  7. get payments_url, headers: valid_headers, as: :json
  8. expect(response).to be_successful
  9. end
  10. end
  11. describe 'GET /show' do
  12. it 'renders a successful response' do
  13. get payment_url(payment), as: :json
  14. expect(response).to be_successful
  15. end
  16. it 'has the correct JSON' do
  17. get payment_url(payment), as: :json
  18. expect(response.parsed_body).to match(a_hash_including(
  19. payment.attributes.slice(
  20. "first_name", "last_name", "address" # ...
  21. )
  22. ))
  23. end
  24. end
  25. end

huangapple
  • 本文由 发表于 2023年4月13日 16:23:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76003241.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定