我们正在添加 PayPal Express Checkout 作为一个选项,用于 checkout 在 Rails 2.3.18 上运行的电子商务应用程序。我已经为我的自定义 PayPal::Merchant::ExpressCheckout
模块编写了代码并进行了一些单元测试,但是我无法理解如何正确地模拟或 stub Controller 方法以便我可以编写集成测试。
我面临的一个问题是,所有 PayPal API 调用都是针对同一个端点 URI,在 POSTed 数据中只有一个操作参数来区分我们正在调用的操作。虽然我已成功设置 FakeWeb 以在我的单元测试中模拟来自 PayPal API 的正确 XML 响应,但在某些集成场景中我需要能够处理背靠背 API 请求。有没有办法告诉 FakeWeb 根据发布的数据做出不同的响应?或者,有没有办法让 FakeWeb 在拦截第一个请求后触发回调方法,以便我可以设置下一个请求?
另一个问题是如何模拟到 PayPal 的重定向。现在,用户单击我们网站上的使用 PayPal 结帐按钮,将他们重定向到我的 ExpressCheckoutsController
上的 setup
方法,该方法获取 token 并设置结帐 URL,然后将用户重定向到那里。我需要在集成测试中模拟两种场景:
1.用户正确提交表单并发送到我的返回URL
2. 用户取消并发送到我的取消网址
有没有一种方法可以在不重写测试文件中的整个 ExpressCheckoutsController 类的情况下做到这一点?
以防万一,我们使用 paypal-sdk-merchant gem。我们的测试环境使用以下 gem:
group :test do
gem 'autotest-rails', '4.1.0'
gem 'ZenTest', '< 4.6'
gem 'fakeweb', '1.2.6'
gem 'mocha', '0.9.4'
gem 'quietbacktrace', '0.1.1'
gem 'factory_girl', '1.2.0'
gem 'thoughtbot-shoulda', '2.10.2', :require => 'shoulda'
gem 'nokogiri', '1.5.6'
gem 'webrat', '0.4.4'
end
更新
我能够通过使用 Mocha stub 我的自定义 ExpressCheckout
模块的 express_checkout_url
方法来解决重定向问题,以便它简单地重定向到 return
或 取消
操作。
PayPal::Merchant::ExpressCheckout.any_instance.stubs(:express_checkout_url).returns(return_order_express_checkout_path)
最佳答案
我了解到 FakeWeb 支持 rotating responses ,虽然这有助于某些集成测试步骤,但我仍然遇到 GetExpressCheckoutDetails
API 方法在 SetExpressCheckout
和 之间被调用的次数不确定的情况DoExpressCheckoutPayment
调用,具体取决于其他几个因素。在深入研究了很多 PayPal::SDK::Core
库之后,我并没有试图弄清楚我需要伪造多少响应,而是在集成测试中使用了这个辅助方法类:
def stub_express_checkout
api = PayPal::SDK::Merchant::API.new
PayPal::Merchant::ExpressCheckout.any_instance.stubs(:express_checkout_url).returns(return_order_express_checkout_path)
FakeWeb.register_uri(
:post,
api.service_endpoint,
:content_type => "application/xml",
:status => ["200", "OK"],
:body => ""
)
PayPal::Merchant::ExpressCheckout.any_instance.stubs(:set_express_checkout).returns(
PayPal::SDK::Merchant::DataTypes::SetExpressCheckoutResponseType.new(api.format_response({
:response => FakeWeb.response_for(:post, api.service_endpoint).tap { |resp|
resp.instance_variable_set("@body", File.read(Rails.root.join("test/fixtures/express_checkout/success/set.xml")))
}
})[:data])
)
PayPal::Merchant::ExpressCheckout.any_instance.stubs(:get_express_checkout).returns(
PayPal::SDK::Merchant::DataTypes::GetExpressCheckoutDetailsResponseType.new(api.format_response({
:response => FakeWeb.response_for(:post, api.service_endpoint).tap { |resp|
resp.instance_variable_set("@body", File.read(Rails.root.join("test/fixtures/express_checkout/success/get.xml")))
}
})[:data])
)
PayPal::Merchant::ExpressCheckout.any_instance.stubs(:do_express_checkout).returns(
PayPal::SDK::Merchant::DataTypes::DoExpressCheckoutPaymentResponseType.new(api.format_response({
:response => FakeWeb.response_for(:post, api.service_endpoint).tap { |resp|
resp.instance_variable_set("@body", File.read(Rails.root.join("test/fixtures/express_checkout/success/do.xml")))
}
})[:data])
)
FakeWeb::Registry.instance.uri_map[FakeWeb::Registry.instance.send(:normalize_uri, api.service_endpoint)] = {}
end
这很丑陋,我不喜欢依赖这么多内部 PayPal::SDK::Core
方法来 stub 我的模块方法,但在我尝试的 2 打方法中,这是最终起作用的方法。
关于paypal - 如何在 Rails 2.3 应用程序中使用 TestUnit 配置 PayPal Express Checkout 的集成测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19546520/