Rails + Rspec: 测试调用服务
Rails + Rspec: Test that service is called
我正在尝试编写一个测试以确保我的服务 WeeklyReportCardService
已实例化并且它的方法 :send_weekly_report_card_for_repositioning
已被调用。
这是控制器:
def update
Audited.audit_class.as_user($user) do
if @check_in.update(check_in_params)
client = Client.find_by(id: check_in_params[:client_id])
if @check_in.repositioning.present? && @check_in.weigh_in.present? && @check_in.client&.location&.name == "World Wide"
# I see this in the console so the if statement returns true
p "hitting send!!"
WeeklyReportCardService.new.send_weekly_report_card_for_repositioning(@check_in.repositioning)
end
render json: @check_in, status: :ok, serializer: API::CheckInsIndexSerializer
else
render json: @check_in.errors.full_messages, sattus: :unprocessable_entity
end
end
end
这是我的测试:
RSpec.describe API::CheckInsController, type: :request do
fit "should send if the client's location is World Wide" do
program = create(:program, :with_client)
worldwide = create(:location, name: "World Wide")
program.client.update(location_id: worldwide.id)
check_in = create(:check_in, client_id: program.client.id, program_id: program.id)
create(:repositioning, check_in_id: check_in.id)
create(:weigh_in, check_in_id: check_in.id)
url = root_url[0..-2] + api_check_in_path(check_in.id) + "?sendReportCardEmail=true"
put url, params: { check_in: {type_of_weighin: 'standard'}}, headers: { "HTTP_AUTHENTICATION": @token }
expect_any_instance_of(WeeklyReportCardService).to receive(:send_weekly_report_card_for_repositioning)
end
end
我看到的错误是:
Failure/Error: DEFAULT_FAILURE_NOTIFIER = lambda { |failure, _opts| raise failure }
Exactly one instance should have received the following message(s) but didn't: send_weekly_report_card_for_repositioning
我还需要做什么来确保函数被调用?
你的顺序错了。您需要先设置期望值,然后才能调用该方法:
expect_any_instance_of(WeeklyReportCardService).to receive(:send_weekly_report_card_for_repositioning)
put url, params: { check_in: {type_of_weighin: 'standard'}}, headers: { "HTTP_AUTHENTICATION": @token }
如果您之后需要设置预期,您需要替换方法或对象 with a spy,如果您更喜欢 arrange-act-assert(或 given-when-then),这将很有用
结构化测试模式。
你还应该注意 the use of any instance is strongly discouraged 并且你可以通过提供一个简单的 class 方法来避免它:
class WeeklyReportCardService
def self.send_weekly_report_card_for_repositioning(...)
new.send_weekly_report_card_for_repositioning(...)
end
end
RSpec.describe API::CheckInsController, type: :request do
it "should send if the client's location is World Wide" do
expect(WeeklyReportCardService).to receive(:send_weekly_report_card_for_repositioning)
put url, params: { check_in: {type_of_weighin: 'standard'}}, headers: { "HTTP_AUTHENTICATION": @token }
end
end
或者通过将 WeeklyReportCardService#new
方法存入 return 模拟或间谍。
我正在尝试编写一个测试以确保我的服务 WeeklyReportCardService
已实例化并且它的方法 :send_weekly_report_card_for_repositioning
已被调用。
这是控制器:
def update
Audited.audit_class.as_user($user) do
if @check_in.update(check_in_params)
client = Client.find_by(id: check_in_params[:client_id])
if @check_in.repositioning.present? && @check_in.weigh_in.present? && @check_in.client&.location&.name == "World Wide"
# I see this in the console so the if statement returns true
p "hitting send!!"
WeeklyReportCardService.new.send_weekly_report_card_for_repositioning(@check_in.repositioning)
end
render json: @check_in, status: :ok, serializer: API::CheckInsIndexSerializer
else
render json: @check_in.errors.full_messages, sattus: :unprocessable_entity
end
end
end
这是我的测试:
RSpec.describe API::CheckInsController, type: :request do
fit "should send if the client's location is World Wide" do
program = create(:program, :with_client)
worldwide = create(:location, name: "World Wide")
program.client.update(location_id: worldwide.id)
check_in = create(:check_in, client_id: program.client.id, program_id: program.id)
create(:repositioning, check_in_id: check_in.id)
create(:weigh_in, check_in_id: check_in.id)
url = root_url[0..-2] + api_check_in_path(check_in.id) + "?sendReportCardEmail=true"
put url, params: { check_in: {type_of_weighin: 'standard'}}, headers: { "HTTP_AUTHENTICATION": @token }
expect_any_instance_of(WeeklyReportCardService).to receive(:send_weekly_report_card_for_repositioning)
end
end
我看到的错误是:
Failure/Error: DEFAULT_FAILURE_NOTIFIER = lambda { |failure, _opts| raise failure }
Exactly one instance should have received the following message(s) but didn't: send_weekly_report_card_for_repositioning
我还需要做什么来确保函数被调用?
你的顺序错了。您需要先设置期望值,然后才能调用该方法:
expect_any_instance_of(WeeklyReportCardService).to receive(:send_weekly_report_card_for_repositioning)
put url, params: { check_in: {type_of_weighin: 'standard'}}, headers: { "HTTP_AUTHENTICATION": @token }
如果您之后需要设置预期,您需要替换方法或对象 with a spy,如果您更喜欢 arrange-act-assert(或 given-when-then),这将很有用 结构化测试模式。
你还应该注意 the use of any instance is strongly discouraged 并且你可以通过提供一个简单的 class 方法来避免它:
class WeeklyReportCardService
def self.send_weekly_report_card_for_repositioning(...)
new.send_weekly_report_card_for_repositioning(...)
end
end
RSpec.describe API::CheckInsController, type: :request do
it "should send if the client's location is World Wide" do
expect(WeeklyReportCardService).to receive(:send_weekly_report_card_for_repositioning)
put url, params: { check_in: {type_of_weighin: 'standard'}}, headers: { "HTTP_AUTHENTICATION": @token }
end
end
或者通过将 WeeklyReportCardService#new
方法存入 return 模拟或间谍。