Turn your manual testers into automation experts Request a DemoStart testRigor Free

Sinatra Testing

Sinatra Testing

Sinatra is a lightweight, open-source web application framework written in Ruby. It is designed to provide a simple and flexible way to create web applications and APIs. Sinatra is often referred to as a “microframework” because of its minimalist approach. It is popular among developers for its ease of use, fast development cycle, and ability to integrate well with other Ruby libraries and tools.

Sinatra provides a routing DSL (domain-specific language) that allows developers to define the routes for their web applications, as well as a simple template engine for rendering views. It also supports middleware, allowing developers to easily add application functionality such as authentication or caching.

When it comes to testing applications built using Sinatra, we can follow the testing pyramid approach. Here're the main testing layers:

Unit Testing

Unit testing forms the base of the testing pyramid, meaning that the majority of your tests ought to be unit tests. The main purpose of writing these tests is to verify that individual units of code, like functions, classes, etc. are giving the expected output. Since these tests are run very often, they need to be lightweight and independent of other modules. Thus you will need to mock other functions or services and provide test data.

Sinatra, being a Ruby-based framework, supports most of the testing tools and frameworks used for testing Ruby code. You can install different gems into your project and get started with creating test suites using them. Let's take a look at the ones that are popularly used.

Using Minitest

Minitest is a popular unit testing framework for Ruby. It provides a variety of testing tools and libraries for writing and running tests, including assertions, test runners, mocks/stubs, and benchmarking tools. It has a simple and flexible syntax for defining tests and assertions, making it easy to write and understand test code.

Minitest is designed to be lightweight and fast, with a minimal overhead that makes it well-suited for testing small to medium-sized Ruby applications. It is also highly extensible, with a plugin system that allows developers to add custom assertions, reporters, and other features to the framework.

Using Rack::Test

Rack::Test is a testing library that provides a simple API for testing Rack-based applications, including Sinatra. It allows you to send HTTP requests to your application and make assertions about the response, making it a great choice for testing the behavior of your application's routes and controllers.

Here is a simple example of a unit test that has three test methods (test_my_default, test_with_params, and test_with_user_agent), each making a different HTTP request to the Sinatra application being tested using the get method provided by Rack::Test.
require 'my_sinatra_app'
require 'minitest/autorun'
require 'rack/test'

class MyAppTest < Minitest::Test
  include Rack::Test::Methods

  def app
    Sinatra::Application
  end

  def test_my_default
    get '/'
    assert_equal 'Hello World!', last_response.body
  end

  def test_with_params
    get '/meet', :name => 'John'
    assert_equal 'Hello, John!', last_response.body
  end

  def test_with_user_agent
    get '/', {}, 'HTTP_USER_AGENT' => 'Hybrid'
    assert_equal "You're using Hybrid!", last_response.body
  end
end

Using RSpec

RSpec is a behavior-driven development (BDD) testing framework for Ruby. It provides a flexible and expressive syntax for defining and running tests. RSpec uses a DSL (domain-specific language) to define tests and expectations. Tests are organized into "describe" and "context" blocks, which define the behavior being tested, and "it" blocks, which define specific test cases or examples. Assertions are defined using "expect" statements, which allow developers to test for specific outcomes or behaviors.

RSpec also includes a variety of built-in matchers for testing common scenarios, as well as support for custom matchers and extensions. It can be run from the command line or integrated into an automated testing suite using tools like Guard or Travis CI.

Mentioned below is a unit test for a Sinatra web application using RSpec and Rack::Test. Setting the APP_ENV environment variable to 'test' is a common practice in Ruby web development to indicate that the application is running in a testing environment. This ensures that any configuration or settings specific to the test environment are being used, rather than those for the production environment.

The required statements load the necessary libraries and dependencies for the test, including the Sinatra application being tested (hello_world.rb), RSpec, and Rack::Test. The RSpec.describe block defines a group of tests or examples for the HelloWorld app. Within this block, the include Rack::Test::Methods statement includes the necessary methods for making HTTP requests and testing the response. The app method is defined to return the instance of the Sinatra application being tested (Sinatra::Application).

The "it" block defines a specific test case or example, in this case, testing whether the app responds with "Hello World" when a GET request is made to the root URL (/). The get method is used to simulate the HTTP request, and the expect statements are used to check that the response is OK and that the response body matches the expected output.
ENV['APP_ENV'] = 'test'

require 'hello_world' # <-- your sinatra app
require 'rspec'
require 'rack/test'

RSpec.describe 'The HelloWorld App' do
  include Rack::Test::Methods

  def app
    Sinatra::Application
  end

  it "says hello" do
    get '/'
    expect(last_response).to be_ok
    expect(last_response.body).to eq('Hello World')
  end
end

Using Test::Spec

Test::Spec is a testing framework for Ruby that provides a more expressive and readable syntax for defining tests than the built-in Test::Unit framework. It is designed to make testing code easier and more natural by allowing developers to describe the behavior of their code in a more human-like way. It can be a good choice for developers who prefer a more minimalistic approach to testing or who want to stick closer to the built-in Test::Unit framework.

Here is an example of a unit test using Test::Spec.
ENV['APP_ENV'] = 'test'

require 'hello_world' # <-- your sinatra app
require 'test/spec'
require 'rack/test'

describe 'The HelloWorld App' do
  include Rack::Test::Methods

  def app
    Sinatra::Application
  end

  it "says hello" do
    get '/'
    last_response.should.be.ok
    last_response.body.should.equal 'Hello World'
  end
end

Integration Testing

The middle tier of the testing pyramid comprises integration tests. These tests should be for those scenarios where different integrations are being made between modules. For example, if a function calls an API to write into the database, you need to check if this integration is working as expected. Some common areas of focus are integrations between different modules, UI components, network systems, databases, classes, functions, helpers, and APIs. You can use the same tools and frameworks used for unit testing, like Minitest, Test::Unit, Rack::Test, or RSpec.

Here is an example of a test meant to check a simple implementation of HTTP authentication. The three test methods in the suite are named test_without_authentication, test_with_bad_credentials, and test_with_proper_credentials. Each of these methods tests a different scenario related to authentication in the Sinatra application.

In the test_without_authentication method, the test makes a GET request to a route that requires authentication and checks that the response status is 401 Unauthorized.

In the test_with_bad_credentials method, the test makes a GET request to the same route but with incorrect credentials and checks that the response status is 401 Unauthorized.

Finally, in the test_with_proper_credentials method, the test makes a GET request to the same route with correct credentials and checks that the response status is 200 OK and the response body is "You're welcome".
ENV['APP_ENV'] = 'test'
require 'test/unit'
require 'rack/test'
require 'application'

class ApplicationTest < Test::Unit::TestCase
  include Rack::Test::Methods

  def app
    Sinatra::Application
  end

  def test_without_authentication
    get '/protected'
    assert_equal 401, last_response.status
  end

  def test_with_bad_credentials
    authorize 'bad', 'user'
    get '/protected'
    assert_equal 401, last_response.status
  end

  def test_with_proper_credentials
    authorize 'admin', 'admin'
    get '/protected'
    assert_equal 200, last_response.status
    assert_equal "You're welcome", last_response.body
  end
end

Using Capybara

Capybara is a Ruby library used for testing. It provides a high-level DSL (Domain-Specific Language) for interacting with web pages in a way that simulates a user's interaction with a web browser. Capybara can be used to simulate user actions such as clicking on links, filling out forms, and submitting data. It also provides a powerful set of matchers for asserting the content of web pages, allowing developers to write tests for the expected behavior of their web applications. Capybara is often used in conjunction with other testing frameworks and supports a variety of drivers for running tests in different web browsers and headless environments. We will dive into its ability to support functional testing in the next section.

For now, let's take a look at an example of using Capybara for integration testing. Here, The include Capybara::DSL statement includes the necessary methods for simulating user interactions with the web application. The setup method is defined to set up the Capybara app to use the Sinatra application being tested. The test_it_works method defines the actual test case or example, in this case, checking that the root URL of the application contains the expected content. The visit method is used to simulate a user visiting the URL, and the assert statement checks that the page contains the expected content.
ENV['APP_ENV'] = 'test'

require 'hello_world' # <-- your sinatra app
require 'capybara'
require 'capybara/dsl'
require 'test/unit'

class HelloWorldTest < Test::Unit::TestCase
  include Capybara::DSL

  def setup
    Capybara.app = Sinatra::Application.new
  end

  def test_it_works
    visit '/'
    assert page.has_content?('Hello World')
  end
end

End-to-End Testing

End-to-end testing involves simulating a user's interaction with an application, examining the various components and modules that are required to complete specific use cases. In the context of booking airline tickets, for instance, a user would navigate through multiple modules to accomplish this task. Therefore, it is crucial to have a solid grasp of the use cases that users typically engage with when utilizing the application. Such information is typically held by QA testers and business analysts.

Involving these team members in the process of developing end-to-end test cases can contribute to better test coverage. End-to-end testing emphasizes the user's perspective, and as a result, the tools employed often interact with the web browser and user interface components.

Now, let's explore options for automating end-to-end testing in a Sinatra-based application.
  • Capybara with Selenium
  • testRigor

Using Capybara with Selenium

You can write end-to-end tests using Capybara and Selenium. Selenium is a popular choice for web automation as it gives the capability to manipulate UI elements using commands that can be written in different languages, including Ruby. By combining Capybara and Selenium, developers can write tests that not only simulate user interactions but also run in a real web browser. This allows for more accurate and comprehensive testing of web applications.

Here is an example of a test case using these two tools. This test creates a new skill and checks that it is successfully created and displayed on the page.
require_relative '../test_helper' 
require 'selenium-webdriver'

class UserCreatesSkillTest < Minitest::Test 
  include Capybara::DSL 
  include TestHelpers 

  Capybara.default_driver = :selenium

  def setup
    Capybara.app = Sinatra::Application.new
  end

  def test_creates_a_skill_with_valid_attributes 
    visit '/' 
    click_link('New Skill') 
    fill_in("skill[name]", with: "Skill name") 
    fill_in("skill[description]", with: "Skill description")  
    select "School", from: "category_id" 
    click_button("Submit") 
    assert_equal '/skills', current_path 
    within("#skill") do 
      assert page.has_content?("Skill name") 
      assert page.has_content?("school") 
    end 
    refute page.has_content?("work") 
  end 
end

Using testRigor

As mentioned earlier, involving team members closely connected to the business in end-to-end testing can provide valuable insights and enhance test coverage. Utilizing a tool that enables users to effortlessly collaborate on and write end-to-end test cases will streamline the test creation process and reduce excessive back-and-forth communication. No-code testRigor system can significantly improve the quality of your testing. Let's examine how this is achieved.

testRigor is an end-to-end test automation tool powered by artificial intelligence, which simplifies many traditional tasks associated with automation testing. Users write test cases in plain English, eliminating the need for programming knowledge - and thus empowering even manual testers to contribute to test automation.

Unlike most other automation testing tools, testRigor does not require specifying element locators such as XPaths. Decoupling from details of implementation brings extra stability (your test won't fail if a locator was accidentally changed), and allows for proper UI-level tests from an end user's perspective. For example, you can simply write "click 'Home' at the top of the page," and testRigor will identify and click on the "Home" element.

As a cloud-based tool, testRigor is scalable and accessible from anywhere, though on-premise setup options are also available. The tool supports cross-platform testing for web, mobile, and desktop. It offers numerous integrations with infrastructure providers such as SauceLabs and BrowserStack for accessing device farms, as well as CI/CD-providing frameworks like Travis and Jenkins to execute test suites efficiently after each deployment.

In testRigor, test suites offer various configurations for HTTP authorization, proxy settings, integrations with other tools or frameworks, screen resolution, and platform testing, among others. Test cases can cover visual testing, audio testing, table data testing, and email and text message testing. Additionally, testRigor allows for API testing and database interaction within test cases. The tool also supports test data generation and importing.

Consider the following example of a testRigor test case. In this scenario, we visit a website allowing an admin to create new skills and make the listing available to other users who can apply. Notice how easy it is to perform operations like referencing UI elements, uploading files, and interacting with table data.
open url "https://learningisfun.org"
login 
compare screen to stored value "Home page"
select "New Skill" from "More"
enter stored value "skillName" into "Skill name"
click on "upload description" to the right of "Skill Description"
enter stored value "skillDescription" into input file "upload-file"
check that page contains "Your skill description was uploaded successfully!" in the middle of the screen
select "School" from "Category" 
click "Submit" 
compare screen to stored value "Home page"
select "Skill Listings" from "More"
check that table "Skills" at row "80" and column "Skill Name" contains stored value "skillName"

Overall, testRigor is the easiest way to build robust and efficient functional test cases fast, while spending minimal time on test maintenance.

How to do End-to-end Testing with testRigor

Let us take the example of an e-commerce website that sells plants and other gardening needs. We will create end-to-end test cases in testRigor using plain English test steps.

Step 1: Log in to your testRigor app with your credentials.

Step 2: Set up the test suite for the website testing by providing the information below:

  • Test Suite Name: Provide a relevant and self-explanatory name.
  • Type of testing: Select from the following options: Desktop Web Testing, Mobile Web Testing, Native and Hybrid Mobile, based on your test requirements.
  • URL to run test on: Provide the application URL that you want to test.
  • Testing credentials for your web/mobile app to test functionality which requires user to login: You can provide the app’s user login credentials here and need not write them separately in the test steps then. The login functionality will be taken care of automatically using the keyword login.
  • OS and Browser: Choose the OS Browser combination on which you want to run the test cases.
  • Number of test cases to generate using AI: If you wish, you can choose to generate test cases based on the App Description text, which works on generative AI.

Step 3: Click Create Test Suite.

On the next screen, you can let AI generate the test case based on the App Description you provided during the Test Suite creation. However, for now, select do not generate any test, since we will write the test steps ourselves.

Step 4: To create a new custom test case yourself, click Add Custom Test Case.

Step 5: Provide the test case Description and start adding the test steps.

For the application under test, i.e., e-commerce website, we will perform below test steps:

  • Search for a product
  • Add it to the cart
  • Verify that the product is present in the cart

Test Case: Search and Add to Cart

Step 1: We will add test steps on the test case editor screen one by one.

testRigor automatically navigates to the website URL you provided during the Test Suite creation. There is no need to use any separate function for it. Here is the website homepage, which we intend to test.

First, we want to search for a product in the search box. Unlike traditional testing tools, you can identify the UI element using the text you see on the screen. You need not use any CSS/XPath identifiers.

For this search box, we see the text “What are you looking for?” So, to activate the search box, we will use the exact text in the first test step using plain English:
click "What are you looking for?"

Step 2: Once the cursor is in the search box, we will type the product name (lily), and press enter to start the search.

type "lily"
enter enter

Search lists all products with the “lily” keyword on the webpage.

Step 3: The lily plant we are searching for needs the screen to be scrolled; for that testRigor provides a command. Scroll down until the product is present on the screen:

scroll down until page contains "Zephyranthes Lily, Rain Lily (Red)"

When the product is found on the screen, testRigor stops scrolling.

Step 4: Click on the product name to view the details:

click "Zephyranthes Lily, Rain Lily (Red)"

After the click, the product details are displayed on the screen as below, with the default Quantity as 1.

Step 5: Lets say, we want to change the Quantity to 3, so here we use the testRigor command to select from a list.

select "3" from "Quantity"
After choosing the correct Quantity, add the product to the cart.
click "Add to cart"

The product is successfully added to the cart, and the “Added to your cart:” message is displayed on webpage.

Step 6: To assert that the message is successfully displayed, use a simple assertion command as below:

check that page contains "Added to your cart:"

Step 7: After this check, we will view the contents of the cart by clicking View cart as below:

click "View cart"

Step 8: Now we will again check that the product is present in the cart, under heading “Your cart” using the below assertion. With testRigor, it is really easy to specify the location of an element on the screen.

check that page contains "Zephyranthes Lily, Rain Lily (Red)" under "Your cart"

Complete Test Case

Here is how the complete test case will look in the testRigor app. The test steps are simple in plain English, enabling everyone in your team to write and execute them.

Click Add and Run.

Execution Results

Once the test is executed, you can view the execution details, such as execution status, time spent in execution, screenshots, error messages, logs, video recordings of the test execution, etc. In case of any failure, there are logs and error text that are available easily in a few clicks.

You can also download the complete execution with steps and screenshots in PDF or Word format through the View Execution option.

testRigor’s Capabilities

Apart from the simplistic test case design and execution, there are some advanced features that help you test your application using simple English commands.

  • Reusable Rules (Subroutines): You can easily create functions for the test steps that you use repeatedly. You can use the Reusable Rules to create such functions and call them in test cases by simply writing their names. See the example of Reusable Rules.
  • Global Variables and Data Sets: You can import data from external files or create your own global variables and data sets in testRigor to use them in data-driven testing.
  • 2FA, QR Code, and Captcha Resolution: testRigor easily manages the 2FA, QR Code, and Captcha resolution through its simple English commands.
  • Email, Phone Call, and SMS Testing: Use simple English commands to test the email, phone calls, and SMS. These commands are useful for validating 2FA scenarios, with OTPs and authentication codes being sent to email, phone calls, or via phone text.
  • File Upload/ Download Testing: Execute the test steps involving file download or file upload without the requirement of any third-party software. You can also validate the contents of the files using testRigor’s simple English commands.
  • Database Testing: Execute database queries and validate the results fetched.

testRigor enables you to test web, mobile (hybrid, native), API, and desktop apps with minimum effort and maintenance.

Additional Resources

Conclusion

When it comes to testing, choosing a good testing process along with testing tools is essential. Out of the many available options, the above tools are some of the most popular ones to choose from. However, the final call depends on your project's requirements, and any tool that is put to the test should be able to meet them.

Join the next wave of functional testing now.
A testRigor specialist will walk you through our platform with a custom demo.