如何在 Capybara 中 POST 到 URL?
刚刚从 Cucumber+Webrat 切换到 Cucumber+Capybara,我想知道如何将内容 POST 到 Capybara 中的 URL。
在 Cucumber+Webrat 中,我能够执行以下步骤:
When /^I send "([^\"]*)" to "([^\"]*)"$/ do |file, project|
proj = Project.find(:first, :conditions => "name='#{project}'")
f = File.new(File.join(::Rails.root.to_s, file))
visit "project/" + proj.id.to_s + "/upload",
:post, {:upload_path => File.join(::Rails.root.to_s, file)}
end
但是,Capybara 文档提到:
访问方法只需要一个 参数,请求方法为 始终获取。始终获取。
如何修改我的步骤,以便 Cucumber+Capybara 对 URL 执行 POST?
Just switched from Cucumber+Webrat to Cucumber+Capybara and I am wondering how you can POST content to a URL in Capybara.
In Cucumber+Webrat I was able to have a step:
When /^I send "([^\"]*)" to "([^\"]*)"$/ do |file, project|
proj = Project.find(:first, :conditions => "name='#{project}'")
f = File.new(File.join(::Rails.root.to_s, file))
visit "project/" + proj.id.to_s + "/upload",
:post, {:upload_path => File.join(::Rails.root.to_s, file)}
end
However, the Capybara documentation mentions:
The visit method only takes a single
parameter, the request method is
always GET.always GET.
How do I modify my step so that Cucumber+Capybara does a POST to the URL?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
正如其他人所说,没有直接的方法可以用 Capybara 进行 POST,因为它完全与浏览器交互有关。对于 API 测试,我非常强烈推荐 rspec_api_documentation gem。
As others have said, there’s no direct way of doing a POST with Capybara because it’s all about browser interaction. For API testing, I’d very highly recommend the rspec_api_documentation gem.
对于使用 RSpec 3+ 的应用程序,您不会希望使用 Capybara 发出 HTTP POST 请求。 Capybara 用于模拟用户行为,并接受由此产生的 JS 行为和页面内容。最终用户不会对应用程序中的资源形成 HTTP POST 请求,用户会单击按钮、单击 ajax 链接、拖放元素、提交 Web 表单等。
请查看 这篇关于 Capybara 和其他 HTTP 方法的博客文章。作者提出以下主张:
因此,无论是否开发 API,如果您必须发出显式 HTTP POST 请求,并且它不涉及 HTML 元素和某种事件(单击、拖动、选择、聚焦等),那么就不应该这样做用水豚进行测试。如果您可以通过单击某个按钮来测试相同的功能,那么请使用 Capybara。
您可能想要的是 RSpec 请求规范 。您可以在此处进行
post
调用以及任何其他 HTTP 方法,并断言对响应的期望。您还可以模拟 n 个存根对象和方法,以断言对请求和响应之间发生的副作用和其他行为的期望。With an application using RSpec 3+, you would not want to make an HTTP POST request with Capybara. Capybara is for emulating user behavior, and accepting the JS behavior and page content that results. An end user doesnt form HTTP POST requests for resources in your application, a user clicks buttons, clicks ajax links, drags n drops elements, submits web forms, etc.
Check out this blog post on Capybara and other HTTP methods. The author makes the following claim:
So, developing an API or not, if you have to make an explicit HTTP POST request, and it does not involve an HTML element and some sort of event (click, drag, select, focusout, whatever), then it shouldn't be tested with Capybara. If you can test the same feature by clicking some button, then do use Capybara.
What you likely want is RSpec Request specs. Here you can make
post
calls, and any other HTTP method as well, and assert expectations on the response. You can also mock n stub objects and methods to assert expectations in regards to side effects and other behaviors that happen in between your request and the response.虽然这不是问题的确切答案,但对我来说最好的解决方案是使用 Capybara 来模拟用户交互的规范(使用
visit
),并使用 Rack Test 来测试 API(如请求)。它们可以在同一测试套件中一起使用。将以下内容添加到规范帮助程序中可以访问
get
、post
和其他机架测试方法:您可能需要将机架测试规范放入
spec/requests 中
文件夹。Although, not an exact answer to the question, the best solution for me has been to use Capybara for specs that simulate user interaction (using
visit
), and Rack Test for test API like requests. They can be used together within the same test suite.Adding the following to the spec helper gives access to
get
,post
and other Rack test methods:You may need to put the Rack Test specs in a
spec/requests
folder.我知道答案已被接受,但我想提供更新的答案。这是 Anthony Eden 和 Corey Haines 将 Rack::Test 传递给 Cucumber 的 World 对象:
使用 Cucumber 和 Rack::Test 测试 REST API
通过这种技术,我能够在步骤定义内直接发送 post 请求。在编写步骤定义时,从 Rack::Test API 自己的 规格。
I know the answer has already been accepted, but I'd like to provide an updated answer. Here is a technique from Anthony Eden and Corey Haines which passes Rack::Test to Cucumber's World object:
Testing REST APIs with Cucumber and Rack::Test
With this technique, I was able to directly send post requests within step definitions. While writing the step definitions, it was extremely helpful to learn the Rack::Test API from it's own specs.
更新答案 2022-10-05
如果您的驱动程序没有
post
(例如,Poltergeist 没有),您可以执行以下操作:我们现在可以在
response.body< 上断言/代码>。
您还可以直接使用
integration_session.post(…)
,但我认为如果不将 POST 会话与测试的普通会话分开,可能会导致一些混乱。正如其他地方所述,在水豚测试中,您通常希望像用户一样通过提交表单来执行 POST。我使用上面的内容来测试如果 POST 在另一个会话中发生(通过 WebSockets),用户会发生什么,所以表单不会削减它。
文档:
2014-06-22 的旧答案
如果您的驱动程序没有
post
(例如,Poltergeist 没有),您可以这样做:但请注意,此请求发生在新会话中,因此您必须通过
response
对象对其进行断言。文档:
Updated answer 2022-10-05
If your driver doesn't have
post
(Poltergeist doesn't, for example), you can do this:We can now e.g. assert on
response.body
.You can also use
integration_session.post(…)
directly, but I think that can cause some confusion by not separating the POST session from the test's ordinary session.As has been stated elsewhere, in a Capybara test you typically want to do POSTs by submitting a form just like the user would. I used the above to test what happens to the user if a POST happens in another session (via WebSockets), so a form wouldn't cut it.
Docs:
Old answer from 2014-06-22
If your driver doesn't have
post
(Poltergeist doesn't, for example), you can do this:But note that this request happens in a new session, so you will have to go through the
response
object to assert on it.Docs:
Capybara 的
visit
仅执行 GET 请求。这是设计使然。用户要执行
POST
,他必须单击按钮或提交表单。没有其他方法可以使用浏览器来执行此操作。测试此行为的正确方法是:
如果您想测试 API,我建议使用
spec/request
而不是 cucumber,但这只是我的想法。Capybara's
visit
only does GET requests. This is by design.For a user to perform a
POST
, he must click a button or submit a form. There is no other way of doing this with a browser.The correct way to test this behaviour would be:
If you want to test an API, I recommend using
spec/request
instead of cucumber, but that's just me.最近,我发现了这篇很棒的博客文章。这对于像托尼这样的情况非常有用,并且您确实想在您的杯子中发布一些内容:
对于我的情况,这变成了:
More recently I found this great blog post. Which is great for the cases like Tony and where you really want to post something in your cuke:
For my case this became:
您可以这样做:
:post
替换为您关心的任何方法,例如:put
或:delete
。your_path
替换为您想要的 Rails 路径,例如rack_test_session_wrapper.submit :delete, document_path(Document.last), nil
会删除我的应用程序中的最后一个文档。You could do this:
:post
which whatever method you care about e.g.:put
or:delete
.your_path
with the Rails path you want e.g.rack_test_session_wrapper.submit :delete, document_path(Document.last), nil
would delete the last Document in my app.