Lesson 3
Implementing Request and Authentication Tests for ToDo Service
Introduction

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.

Writing Request Specs

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.

Ruby
1describe "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 for 201 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:

Ruby
1require '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): Expects 200 OK status.
  • todos = JSON.parse(response.body): Parses response.
  • expect(todos.length).to eq(1): Verifies todos count.
Authentication Tests

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:

Ruby
1require '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): Expects 201 Created.
  • message = JSON.parse(response.body): Parses response.
  • expect(message['message']).to eq('User created successfully'): Checks success message.

Add the following test:

Ruby
1describe "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): Expects 200 OK.
  • token = JSON.parse(response.body)['token']: Extracts token.
  • expect(token).to be_present: Checks token presence.
Summary and Next Steps

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!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.