【问题标题】:Testing function contains an API request测试函数包含一个 API 请求
【发布时间】:2018-04-16 00:05:27
【问题描述】:

我正在尝试使用 Stripe API 测试我的 Rails 应用程序,所以我从模型开始,我正在使用 Rspec,我要测试的模型称为 bank_account.rb 里面有一个名为 (create_bank_account ) 带有参数 (bank_token) 它的伪代码是这样的:

def create_bank_account(bank_token)
  # make a Stripe request and save it in local variable
  # save needed data in my bank_account table in my DB
end

当我开始测试这个函数时,我发现里面有一个API调用,不好,我需要我的测试不依赖互联网,所以搜索后我找到了'StripeMock' gem,它很有用我开始将它与 Rspec 一起使用,但我发现自己正在编写这样的测试:

it 'with valid bank_token` do
  # create a double for bank_account
  # using StripeMock to get a faked response for creating
  # new bank_account
  # expect the doube to receive create_bank_account
  # function and response with saving the data inside the DB
end

但在写完这篇文章后,我注意到我实际上并没有运行 create_bank_account 函数,我伪造了它,所以我的问题是:

1- 我如何测试包含 API 请求的函数但运行它自己而不是伪造的函数?

2- 我阅读了很多关于何时使用双精度和存根的信息,我的理解是当函数未完成时,但如果函数已经实现,我应该使用双精度来避免调用 API 之类的函数吗?

【问题讨论】:

  • 您可以只使用 api 调用而不是函数本身的存根。例如说 api 调用由 Sendgrid.send() 完成,然后你可以单独由 Sendgrid.stub(:send).with('more_than', 'one_argument') 存根。

标签: ruby-on-rails ruby testing stripe.net


【解决方案1】:

首先:

  • 不要为bank_account 创建双精度。
  • 不要模拟/存根bank_account.create_bank_account

如果你在一个应该测试BankAccount#create_bank_account行为的测试中做这些事情,那么你的测试毫无价值。

(为了证明这一点,请尝试在方法中编写损坏的代码。您的测试显然应该失败。但如果您在模拟该方法,一切都会继续通过!!)

无论如何,您应该模拟stripe 请求,即在您的应用程序和互联网之间的边界处的行为。

如果没有更多信息,我无法提供工作代码示例,但从广义上讲,您可以从中重构代码:

def create_bank_account(bank_token)
  # make a Stripe request and save it in local variable
  # save needed data in my bank_account table in my DB
end

到这里:

def create_bank_account(bank_token)
  stripe_request = make_stripe_request(bank_token)
  # save needed data in my bank_account table in my DB
end

private

def make_stripe_request(bank_token)
  # ...
end

...然后在您的测试中,您可以通过use StripeMock伪造BankAccount#make_stripe_request 的响应。

如果代码不是那么容易重构(?!),那么像这样直接存根Stripe 库可能不切实际。您始终可以采用的另一种方法是使用像 webmock 这样的库来简单地拦截所有 HTTP 调用。

【讨论】:

  • 说这是请求创建新bank account 的响应格式,我将idbank_name 保存到我的数据库中,然后从你的回答中我应该只测试make_stripe_request 而不是测试 create_bank_account?我说的对吗?
  • 我的意思是我正在测试 create_bank_account 对吗?所以 create_bank_account 中的每一行都应该运行,这可能吗?或者因为我不想调用真正的服务器而不可能?谢谢
  • 您的测试实际上想要达到什么目的?我想它类似于bank_account.create_bank_account; expect(bank_account.bank_name).to eq("Big Money")?同样,我需要更多信息来提供具体答案,但我强烈怀疑它您应该测试的BankAccount#create_bank_account 方法。
  • 所以不;根据我的回答,您的测试应该只call BankAccount#create_bank-account,但应该只stub BankAccount#make_string_request
  • 正如我上面所建议的,如果您不想存根 any 代码,那么我建议只模拟 HTTP 调用(通过 webmock)而不是条纹对象本身。
猜你喜欢
  • 2017-06-05
  • 2020-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-12
  • 1970-01-01
相关资源
最近更新 更多