Welcome to our lesson on implementing request and authentication tests for the ToDo service in your Ruby on Rails application. Unit testing is an essential part of software development, helping you ensure that your application behaves as expected and is free from bugs. In this lesson, we will continue putting our focus on using RSpec
to write and run tests for various functions of our ToDo service, such as creating and retrieving todos.
By the end of this lesson, you will be able to write comprehensive unit tests for your ToDo service and understand how these tests contribute to the stability and reliability of your application.
Request specs in RSpec
allow you to simulate HTTP requests to your application and inspect the responses. Let’s write tests for the ToDo
model.
Ruby1describe "POST /todos" do 2 it "creates a new todo" do 3 todo_params = { title: 'Test Todo', description: 'Test Desc' } 4 5 post todos_path, params: { todo: todo_params }, headers: { 'Authorization': "Bearer #{token}" } 6 7 expect(response).to have_http_status(:created) 8 todo = JSON.parse(response.body) 9 expect(todo['title']).to eq('Test Todo') 10 end 11end
describe "POST /todos" do
: Starts testing "POST /todos".it "creates a new todo" do
: Tests creation of a new todo.todo_params = { title: 'Test Todo', description: 'Test Desc' }
: Defines new todo parameters.post todos_path, params: { todo: todo_params }, headers: { 'Authorization': "Bearer #{token}" }
: Sends a POST request with authentication.expect(response).to have_http_status(:created)
: Checks for201 Created
status.todo = JSON.parse(response.body)
: Parses response to JSON.expect(todo['title']).to eq('Test Todo')
: Verifies the todo's title.
Continuing in the same file, add the following test:
Ruby1require 'rails_helper' 2 3RSpec.describe "Todos", type: :request do 4 let(:user) { User.create(username: 'testuser', password: 'testpass') } 5 let(:token) { JWT.encode({ user_id: user.id }, Rails.application.credentials.secret_key_base) } 6 7 describe "GET /todos" do 8 it "returns all todos" do 9 get todos_path, headers: { 'Authorization': "Bearer #{token}" } 10 11 expect(response).to have_http_status(:success) 12 todos = JSON.parse(response.body) 13 expect(todos.length).to eq(1) 14 end 15 end 16end
require 'rails_helper'
: Sets up test environment.RSpec.describe "Todos", type: :request do
: Begins "Todos" request tests.let(:user) ... }
: Creates a user for testing.let(:token) ... ) }
: Generates JWT token.describe "GET /todos" do
: Tests "GET /todos".it "returns all todos" do
: Checks fetching of todos.get todos_path, ...
: Sends GET request with token.expect(response).to have_http_status(:success)
: Expects200 OK
status.todos = JSON.parse(response.body)
: Parses response.expect(todos.length).to eq(1)
: Verifies todos count.
Authentication is crucial for securing endpoints. Let's write tests for user registration and login.
Create a new file named spec/requests/authentication_spec.rb
and add the following test:
Ruby1require 'rails_helper' 2 3RSpec.describe "Authentication", type: :request do 4 describe "POST /register" do 5 it "registers a new user" do 6 user_params = { username: 'newuser', password: 'newpass' } 7 8 post register_path, params: { user: user_params } 9 10 expect(response).to have_http_status(:created) 11 message = JSON.parse(response.body) 12 expect(message['message']).to eq('User created successfully') 13 end 14 end 15end
require 'rails_helper'
: Sets up test environment.RSpec.describe "Authentication", type: :request do
: Begins authentication tests.describe "POST /register" do
: Tests registration.it "registers a new user" do
: Verifies user registration.user_params = { ... }
: Sets registration data.post register_path, ...
: Sends POST request.expect(response).to have_http_status(:created)
: Expects201 Created
.message = JSON.parse(response.body)
: Parses response.expect(message['message']).to eq('User created successfully')
: Checks success message.
Add the following test:
Ruby1describe "POST /login" do 2 let!(:user) { User.create(username: 'testuser', password: 'testpass') } 3 4 it "logs in a user" do 5 login_params = { username: 'testuser', password: 'testpass' } 6 7 post login_path, params: login_params 8 9 expect(response).to have_http_status(:ok) 10 token = JSON.parse(response.body)['token'] 11 expect(token).to be_present 12 end 13end
describe "POST /login" do
: Tests login endpoint.let!(:user) ... }
: Prepares a user for login.it "logs in a user" do
: Validates user login.login_params = { ... }
: Defines login credentials.post login_path, ...
: Sends POST request.expect(response).to have_http_status(:ok)
: Expects200 OK
.token = JSON.parse(response.body)['token']
: Extracts token.expect(token).to be_present
: Checks token presence.
We’ve covered a lot in this lesson: you learned how to write request specs for ToDo
and authentication endpoints. These tests are vital for ensuring that your application functions correctly and securely.
As this is the last lesson of the course, I want to congratulate you on your progress. You now have a strong foundation in securing and testing your Ruby on Rails app. Next, practice what you’ve learned by completing the exercises provided. Thank you for completing the course, and happy coding!