This is the fourth post in the series on building a web application without using Rails. In the last post, we saw how to dynamically render the views templates. This post is all about testing.
As we add more features to our Rack-based web application, it’s getting difficult and tedious to manually test our application in the browser. It’s important to make sure that as we add new features or refactor the code, we don’t break the application. In this article, we will set up tests using the Rack::Test
library along with RSpec
.
Rack::Test
Rack::Test
is a small, simple testing API for Rack apps. It can be used on its own or as a reusable starting point for Web frameworks and testing libraries to build on.
It provides the following features:
- Allows for submitting requests and testing responses
- Maintains a cookie jar across requests
- Supports request headers used for subsequent requests
- Follow redirects when requested
RSpec
RSpec is a ruby testing library. You can also use Minitest. Let’s use bundler to install rack-test
and rspec
gems.
bundle add rack-test
bundle add rspec
Now create a spec
directory and add a spec_helper.rb
in it.
mkdir spec
touch spec/spec_helper.rb
We will require the rack/test
library along with our application in the spec_helper
, so we don’t need to worry about them when writing specs.
require 'rack/test'
require_relative '../app'
RSpec.configure do |config|
config.include Rack::Test::Methods
end
Let’s add our first test that tests the home page. Create a spec/app_spec.rb
file with the following test.
require 'spec_helper'
RSpec.describe App do
let(:app) { App.new }
let(:response_body) do
<<~BODY
<html>
<head>
<title>Application</title>
<link rel="stylesheet" href="/public/style.css">
<meta charset="utf-8">
</head>
<body>
<main>
<h1>Greetings from Rack</h1>
</main>
</body>
</html>
BODY
end
it 'can access the home page' do
get '/'
expect(last_response.status).to eq 200
expect(last_response.body).to eq(response_body)
end
end
To run the spec, use the rspec
command. The spec should pass. If you run into any problems, let me know.
➜ web git:(main) ✗ rspec
Finished in 0.01113 seconds (files took 0.16989 seconds to load)
1 example, 0 failures
Congratulations, we have our first passing test. Let’s add another spec for the favicon.
it 'can read the favicon' do
get '/favicon.ico'
expect(last_response.status).to eq(200)
expect(last_response.body).to eq('favicon')
end
The specs should still pass. This is pretty nice as we now have specs covering our entire application. We will build the future features in this series by writing a failing test and then making the test pass.
RSpec supports a .rspec
configuration file, that lets you skip the spec_helper
require in your spec files and also pretty-print the output in a nice document format that reads like English.
First, add a .rspec
file in the root directory
touch .rspec
Add following content in it:
--color
--format documentation
--require spec_helper
If you run the rspec
command now, you will get the following output:
➜ web git:(main) ✗ rspec
App
can access the home page
can read the favicon
Finished in 0.00969 seconds (files took 0.16714 seconds to load)
2 examples, 0 failures
Which is really nice, especially when our test suite gets larger and larger.
That’s it. I hope you learned something new. In the next article, we will learn how to add routing and controller support to our Rack application. This will allow use to use the separation-of-concerns principle to organize our application.