Rack::Test is a request helper small enough to read in one sitting
Rack::Test is a small, simple testing API for Rack apps.
At a glance
- What is it?
- Rack::Test gives a Ruby test case the ability to make requests against a Rack application and inspect the response, with a cookie jar that survives from one request to the next, headers that carry over, and optional redirect following. It is not a framework, and the README says so directly, that it can be used on its own or as a reusable starting point for web frameworks and testing libraries to build on, which is exactly what happened.
- Who is it for?
- Rack::Test suits a Ruby team testing a Rack application, and it suits a framework author who wants a request helper for their own test suite rather than a heavier harness.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 33 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A mixin rather than a framework
The description is that Rack::Test is a small, simple testing API for Rack apps, and that it can be used on its own or as a reusable starting point for web frameworks and testing libraries to build on. That second clause is the design brief, because the library is deliberately tiny. A test case includes `Rack::Test::Methods` and defines an `app` method, and the test case then has verbs available on it, `get`, `post`, `delete` and the rest, with the result left in `last_response`. The example in the readme is short enough to see the whole shape, and it is written with `test/unit`, although the readme is explicit that rack-test works equally well with minitest or rspec, which tells you the library has no opinion about your test framework. What the framework needs to supply is an `app` method, and the readme shows that being either a lambda that returns a response or the real application.
The cookie jar is what makes it more than a helper
The feature list has four items and the second is the one that matters most. It allows submitting requests and testing responses, it maintains a cookie jar across requests, it supports request headers used for subsequent requests, and it follows redirects when requested. The cookie jar is the difference between a helper and a session-aware client, because in a real application the interesting behaviour is a login followed by an authenticated request, and a helper that forgets the session cookie cannot express that. The header support works the same way, with a header set once applying to the requests that follow, and the example has a commented line showing exactly that, setting an accept-charset header for all requests in the spec. The redirect following is opt in, which is the right default, since a redirect that is silently followed will hide a broken redirect rule from a test that meant to assert on it.
The third argument carries the environment, with three special keys
Most calls take a path and, for a body, a payload, but the third argument is the Rack environment, and the readme documents the entries in it that are treated specially, in addition to the options that `Rack::MockRequest#env_for` supports. The `:cookie` key sets a cookie for the current session before the request is submitted, which is the programmatic way of starting a session with a known identity. The `:query_params` key sets parameters for the query string as opposed to the body, and its value should be a hash of parameters. The `:xhr` key sets the `HTTP_X_REQUESTED_WITH` environment key to `XMLHttpRequest`, which is how a server decides whether a request came from a script. The example posts a JSON body with the content type passed in the environment, which is the third way of setting it, and the delete example shows the other convention, a path with a query string and the parameters as the second argument, where the second argument is used as the request parameters and is included in the body for non-GET requests.
Rack::Lint is the compliance check, and it is opt in
There is a section on Rack::Lint that is easy to skim and worth not skimming. If your application does not automatically use the Rack::Lint middleware in test mode, and you want to test that requests to and responses from your application are compliant with the Rack specification, you should use it manually, and the example wraps your app in it:
class TestApp < Test::Unit::TestCase
include Rack::Test::Methods
APP = Rack::Lint.new(YOUR_APP)
def app
APP
end
endThe value of that is that it checks the specification rather than your intent, so a middleware that returns a body where a Rack application must return an enumerable, or sets a header in the wrong form, is caught by a test rather than by a browser in production. The catch is that it only works if it is actually enabled, and the readme is careful to say the automatic behaviour depends on your application.
Testing the middleware stack, not just the app
The other testing pattern in the readme addresses a common gap. If you are loading middleware in a `config.ru` file and want to test that, you should load the Rack application created from the `config.ru` file rather than the bare application, and the example shows the one line that does it:
OUTER_APP = Rack::Builder.parse_file("config.ru").first
class TestApp < Test::Unit::TestCase
include Rack::Test::Methods
def app
OUTER_APP
end
def test_root
get "/"
assert last_response.ok?
end
endThe reason this matters is that most of what a Rack application does at the edge is middleware, and a test suite that bypasses the stack is testing something the users do not run. Parsing the config file gives you the same stack the server builds, which means the session middleware, the error handling and the body parsers are all in the path while the test runs.
Merb 1.0 is where this came from
The authors section credits contributions from Bryan Helmkamp, Jeremy Evans, Simon Rozet and others, and then adds that much of the original code was extracted from the request helper of Merb 1.0. That history explains the shape of the library, because it is a request helper lifted out of a web framework and given a home of its own, and the design decisions are the ones that made sense inside a framework. The supported platforms are Ruby 2.0 or later and JRuby 9.1 or later, which dates the project accurately. The repository layout follows the same vintage, with a `lib/` directory, a `spec/` directory, a `Rakefile`, a `History.md` and a `rack-test.gemspec`, and the release instructions in the readme are the manual, versioned steps of that era, where you bump the version in `lib/rack/test/version.rb`, update `History.md` with the version and the date, commit, tag, push the tags, build the gem, push the gem and then post a discussion for the release. The readme also asks contributors to use a regular forking workflow, to write tests for new or changed behaviour, to explain the motivation in the commit or pull request message, and to keep `History.md` updated.
How current is it, and what should you check
The interesting question about this repository is the gap between the activity and the releases. The last push to the repository was on 2026-09-20, so work is still landing, but the listed releases are v1.1.0 from 2018-07-22, v1.0.0 from 2018-03-28 and v0.8.3 from 2018-03-13. That means the gem on RubyGems is eight years old while the repository is not, and the gap is where the risk lives, since a security fix or a Rack specification change in the repository will not have reached the published gem. So the first thing to check is which version your bundle actually resolves and whether it matches the code you are reading. The second is whether the framework you use already provides its own request helper, since several Rack frameworks ship one and the readme's own claim, that this is a starting point for frameworks to build on, means that many of them did exactly that. The third is the `Rack::Lint` question from earlier, and the installation itself is the least interesting part, a `gem install rack-test` or a line in the Gemfile.
Editorial conclusion
Rack::Test suits a Ruby team testing a Rack application, and it suits a framework author who wants a request helper for their own test suite rather than a heavier harness. It is a poor fit if you need HTTP client features it does not have, since it is a test helper for an in-process app rather than a general client, and it is a poor fit if you are on a modern Ruby and expect the gem to move, since the last tagged release here is from 2018 even though the repository is still being pushed to. Before you depend on it, check three things: that your framework already ships its own test helper, since several do, that the version you resolve still behaves as the README describes, given how long ago the last release was, and whether the Rack specification compliance check through `Rack::Lint` is switched on in your test mode, since a middleware that breaks the spec is otherwise easy to miss.
Frequently asked questions
What is Rack::Test?
A small, simple testing API for Rack applications, used on its own or as a reusable starting point for web frameworks and testing libraries to build on. A test case includes Rack::Test::Methods, defines an app method and then has get, post and delete verbs, with the result available as last_response.
What does Rack::Test give me that a plain HTTP client does not?
A cookie jar that is maintained across requests, request headers that carry over to subsequent requests, and optional redirect following. The cookie jar is what lets a test express a login followed by an authenticated request.
How do I test a Rack application for specification compliance?
Use the Rack::Lint middleware, which the readme says is needed when your application does not automatically use it in test mode. Wrapping the app in it, with `APP = Rack::Lint.new(YOUR_APP)`, checks that requests to and responses from the application comply with the Rack specification.
How do I test the middleware in my config.ru with Rack::Test?
Load the application the server would build with `OUTER_APP = Rack::Builder.parse_file("config.ru").first` and return that from the app method, so the test exercises the same stack the users run rather than the bare application.
Is Rack::Test still maintained?
The repository is still being pushed to, with the last change on 2026-09-20, but the published releases are old, with v1.1.0 from 2018-07-22, v1.0.0 from 2018-03-28 and v0.8.3 from 2018-03-13. It supports Ruby 2.0 and later and JRuby 9.1 and later, and it is MIT licensed.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/rack-rack-test)Was this useful?