Reputation: 1864
I'm new to testing with RSpec
and don't know how to fix this error while test creating a new Customer
where my 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
where generate_verification_code
and send_verification_code
in 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
and test file for registrations_controller_spec.rb
for Customer
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
I got this error, after running the test:
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
I got it that this error is happening because in testing it shouldn't call external Api (when Twilio send sms verification code to number)!
But any ideas how to solve this ?
Upvotes: 0
Views: 2507
Reputation: 15654
The reason why this is happening is that your tests are trying to hit twilio's API and probably don't have correct configuration for test environment. For testing third party calls like Twilio, you need to mock HTTP requests. Someone has suggested VCR in comments. However, in my opinion, you should mock the TwilioClient itself by creating a fake twilio adapter. Something like this –
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
Change send_verification_code
method in Customer to –
def send_verification_code
client = TwilioAdapter.new
client.send_sms(
to: customer.mobile_phone_number,
body: "Your verification code is #{verification_code}"
)
end
Now you in before block of controller test, mock TwilioAdapter's send_sms method.
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
…
That should do the trick.
In any case, I strongly discourage this pattern of making 3rd part calls synchronously via models. I recommend creating an SMS service with a generic interface that uses the above mention twilio adapter for sending sms and do this asynchronously using sidekiq. https://www.twilio.com/blog/2015/10/delay-api-calls-to-twilio-with-rails-active-job-and-sidekiq.html
Upvotes: 2