我是RSpec
测试新手,不知道如何在测试创建新Customer
时修复此错误,我的CustomerController
class Api::V1::Customers::RegistrationsController < DeviseTokenAuth::RegistrationsController
def create
customer = Customer.new(email: params[:email],
password: params[:password],
password_confirmation: params[:password_confirmation],
first_name: params[:first_name],
last_name: params[:last_name],
telephone_number: params[:telephone_number],
mobile_phone_number: params[:mobile_phone_number])
if customer.save
customer.generate_verification_code
customer.send_verification_code
render json: {message: 'A verification code has been sent to your mobile. Please fill it in below.'}, status: :created
else
render json: customer.errors
end
end
end
end
generate_verification_code
和send_verification_code
在Customer
class Customer < ActiveRecord::Base
def generate_verification_code
self.verification_code = rand(0000..9999).to_s.rjust(4, "0")
save
end
def send_verification_code
client = Twilio::REST::Client.new
client.messages.create(
from: Rails.application.secrets.twilio_phone_number,
to: customer.mobile_phone_number,
body: "Your verification code is #{verification_code}"
)
end
end
和测试文件,用于Customer
registrations_controller_spec.rb
require 'rails_helper'
RSpec.describe Api::V1::Customers::RegistrationsController, type: :controller do
let(:customer) { FactoryBot.create(:customer) }
before :each do
request.env['devise.mapping'] = Devise.mappings[:api_v1_customer]
end
describe "Post#create" do
it 'creates a new customer' do
post :create, params: attributes_for(:customer)
expect(response).to have_http_status(:created)
end
end
end
运行测试后,我收到此错误:
Failure/Error:
client.messages.create(
from: Rails.application.secrets.twilio_phone_number,
to: customer.mobile_phone_number
body: "Your verification code is #{verification_code}"
)
Twilio::REST::RestError:
Unable to create record: The requested resource /2010-04-01/Accounts//Messages.json was not found
我知道这个错误正在发生,因为在测试中它不应该调用外部 API(当 Twilio 向号码发送短信验证码时(!
但是有什么想法可以解决这个问题吗?
发生这种情况的原因是您的测试正在尝试访问 twilio 的 API,并且可能没有针对测试环境的正确配置。要测试像Twilio这样的第三方调用,你需要模拟HTTP请求。有人在评论中建议VCR。但是,在我看来,您应该通过创建一个虚假的 twilio 适配器来模拟 TwilioClient 本身。像这样的东西——
class TwilioAdapter
attr_reader :client
def initialize(client = Twilio::REST::Client.new)
@client = client
end
def send_sms(body:, to:, from: Rails.application.secrets.twilio_phone_number)
client.messages.create(
from: from,
to: to,
body: body,
)
end
end
将客户中的send_verification_code
方法更改为 –
def send_verification_code
client = TwilioAdapter.new
client.send_sms(
to: customer.mobile_phone_number,
body: "Your verification code is #{verification_code}"
)
end
现在你在控制器测试块之前,模拟TwilioAdapter的send_sms方法。
require 'rails_helper'
RSpec.describe Api::V1::Customers::RegistrationsController, type: :controller do
let(:customer) { FactoryBot.create(:customer) }
before :each do
request.env['devise.mapping'] = Devise.mappings[:api_v1_customer]
# Here's the expectation
expect_any_instance_of(TwilioAdapter).to receive(:send_sms).with(hash_including(:body, :to))
end
…
这应该可以解决问题。
无论如何,我强烈反对这种通过模型同步进行第 3 部分调用的模式。我建议创建一个带有通用接口的 SMS 服务,该服务使用上面提到的 twilio 适配器发送 SMS,并使用 sidekiq 异步执行此操作。https://www.twilio.com/blog/2015/10/delay-api-calls-to-twilio-with-rails-active-job-and-sidekiq.html