Translate

quarta-feira, 10 de março de 2021

Processo para realizar os testes de software

 

Processo de Desenvolvimento e Teste
Processo de Desenvolvimento e Teste

Em um processo de desenvolvimento de software, encontramos diferentes atividades que precisam ser realizadas para que um sistema seja disponibilizado para os usuários finais, como pode ser observado na figura acima. Se pensarmos em um processo genérico, sem levarmos em consideração se são processos ágeis ou tradicionais, encontramos um conjunto de passos e artefatos para essa finalidade.


A primeira coisa que precisamos criar antes de desenvolver um sistema é a sua documentação. Há diferentes formas de descrever essa documentação, como por exemplo, casos de uso, user stories, lista de requisitos, backlog list, entre outras.

No entanto, para verificar se o sistema foi construído conforme a sua documentação, existem atividades que são realizadas com esse objetivo. O teste de software é a arte de realizar uma simulação em um software, com o objetivo de encontrar defeitos. ¹ Esses testes podem ser realizados de forma planejada em paralelo ao desenvolvimento do sistema. Para isso é importante criar um roteiro de teste, que é composto por um conjunto de casos de teste. Esses casos de teste descrevem cenários com base nas regras de negócio descritas para o sistema.

Durante a execução dos testes, o sistema pode conter erros que devem ser cadastrados em um relatório de defeitos. Esse relatório é enviado para o desenvolvedor, para que ele possa reproduzir os defeitos e corrigi-los. Assim que os defeitos forem corrigidos, é importante realizar uma atividade de reteste para confirmar se o sistema não possui mais os erros encontrados.

Apesar da atividade de teste de software ter a intenção de livrar o sistema de erros, no entanto os testes conseguem identificar apenas a presença de defeitos, mas não a ausência deles. ²

Dessa forma, à medida que o sistema é testado e os erros são corrigidos, ainda no ambiente de desenvolvimento, mais confiança a equipe possui ao lançar o sistema em produção. Dessa forma, há uma chance maior de o sistema ser aceito pelos usuários e também há uma redução com manutenção de sistema referente à erros em produção.

Referências:

¹ MYERS, G. J. The Arts of Software Testing.

² Dijkstra, E. A Case against the GO TO Statement.

segunda-feira, 25 de janeiro de 2021

A Pirâmide de teste e os Testes end-to-end

 





Testes “end-to-end” (E2E testing) são uma maneira de realizar testes atravessando todas as camadas da arquitetura de um sistema. Os testes são realizados do início ao fim, por exemplo, em uma arquitetura de sistema MVC (Model-View-Controller) os testes são realizados na camada de apresentação (view), validadando regras de negócio tratadas pelo controlador (controller) chegando até o modelo (model), onde os dados podem ser gravados e lidos a partir de um banco de dados.

No entanto, essa definição de E2E não parece muito diferente dos testes de sistema, que são testes que tratam o sistema como uma caixa-preta, cujos dados são passados em uma tela do sistema e o usuário recebe uma resposta na mesma interface do sistema.

Se observarmos a pirâmide de teste acima, nós percebemos que os testes E2E podem ser classificados como horizontal e vertical.
  • E2E horizontal: quando os testes são realizado em um mesmo nível de teste, considerando todos os fluxos do sistema. Tem como objetivo verificar se os componentes daquela camada, fazem o que deveriam fazer em um determinado contexto.
  • E2E vertical: quando os testes são realizados em vários níveis de teste. Dessa forma é possível identificar problemas nas diferentes camadas do sistema, desde o nível unitário até a integração de todos os componentes. Nesse caso o objetivo é verificar se cada camada do sistema funciona independentemente.

Através da pirâmide de teste, podemos observar que há diferenças conceituais entre testes E2E e testes de sistema.

Testes Funcionais

  1. O teste é limitado a uma única parte do código ou sistema.
  2. Garante que o software testado atende aos critérios de aceitação.
  3. Testa a maneira como um único usuário se envolve com o sistema.
  4. Valida o resultado de cada teste para entradas e saídas.

Testes End-to-End (E2E)

  1. O teste cruza vários sistemas e grupos de usuários.
  2. Garante que um sistema, ou parte dele, continue funcionando após alterações serem feitas.
  3. Testa a maneira como vários usuários interagem no sistema.
  4. Valida se cada etapa do processo foi concluída.

Pirâmide de Teste

Um ponto importante a se observar na Pirâmide de Teste é a sua forma, denotando a proporção de testes que devem ser realizados em cada nível de teste. Assim, os testes unitários devem ser realizados em maior quantidade, em seguida os testes de integração e por fim os testes de sistema.

Isso se deve ao fato que os testes que estão na base da pirâmide (testes unitários) possuem um custo de criação, execução e automação bem menor que os testes do topo da pirâmide. Além disso, em um cenário em que testes unitários e de integração são criados de forma efetiva, vários cenários de testes e regras de negócio podem ser validadas nesses níveis mais baixos. Com isso, é possível reduzir o número de testes de sistema (manuais e/ou automáticos) para os cenários de teste que já foram testados anteriormente em outros níveis.

Se quiser saber mais sobre pirâmide de teste, recomendo o artigo de Martin Fowler: https://martinfowler.com/bliki/TestPyramid.html

Ferramentas para E2E vertical

Testes de sistema (UI):
  • Selenium: realiza testes automáticos através da interface web de uma aplicação, independente da linguagem de programação que ela foi construída. Possui diferentes linguagens de programação, como python, java, ruby, etc. Tem fácil instalação, pois permite realizar testes através de um plugin para o navegador, utilizando o Selenium IDE, sem a necessidade de conhecimentos de programação.
  • Cypress: também realiza testes automáticos através da interface web de uma aplicação. Não depende da linguagem de programação utilizada no desenvolvimento. Os testes são construídos em JavaScript e requer a instalação do NodeJs, ou seja, conhecimentos de programação.

Testes de integração para APIs Rest
  • Cypress: permite realizar testes em API Rest. Os testes são escritos em JavaScript. Além disso, os testes podem ser agregados ao código do sistema, mas eles são executados de forma independente, sem nenhum vínculo às classes do sistema desenvolvido.

Testes unitários
  • JUnit: testes unitários padrão para a linguagem Java.
  • Mocha: testes unitários bastante utilizado por programadores JavaScript.
  • Jest: testes unitários desenvolvidos pelo Facebook e é bastante utilizado por programadores React.

Há outras ferramentas que podem ser utilizadas para outras finalidades. Gostei bastante do material desse blog abaixo: https://talkingabouttesting.com/2018/10/05/um-review-pessoal-de-ferramentas-para-testes-automatizados-no-mundo-javascript-parte-1/

Basicamente, a regra básica para garantir uma maior qualidade nos sistemas é comece a testar o mais cedo, se possível antes mesmo de criar a primeira linha de código. Separe os testes em diferentes níveis, para que cada tipo de teste detecte os possíveis erros de acordo com os objetivos de cada um. Não perca tempo testando o que já foi testado nos níveis anteriores.

quinta-feira, 12 de novembro de 2020

Como testar uma Rails API com Rspec

 

Primeiramente, será apresentado como criar uma API Rest usando Rails 5.0 a partir da API de clima disponível no site https://openweathermap.org/api. Em seguida, será instalado o pacote RSpec de Rails para que seja possível executar os testes dessa API.

Pré-requisitos

Criando uma API Rest com Ruby on Rails

Para criar uma API com Rails é necessário que seja feita a instalação completa do Rails 5.0 na sua máquina.

No terminal entrar na pasta do seu workspace e digitar o comando para criar um novo projeto de API em rails:

C:/workspace>rails new climateapi --api
Observe que esse projeto difere dos outros projetos por haver o termo ‘api

Com a aplicação criada, entrar na pasta do projeto criado e digitar o comando para instalar todas as bibliotecas do projeto.

C:/workspace/climateapi>bundle install
Caso ocorra algum erro referente ao sqlite, basta alterar no arquivo /climateapi/Gemfile.
gem 'sqlite3', '< 1.4'
gem 'rack-cors'

Em seguida, executar novamente o comando ‘bundle install’.

Na pasta config adicionar ao arquivo application.rb a configuração do Cors, que autoriza essa API ser utilizada por outros sistemas. 

#adicionar esse trecho do código
config.middleware.insert_before 0, "Rack::Cors" do .. end
require_relative 'boot'
require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_view/railtie"
require "action_cable/engine"
# require "sprockets/railtie"
require "rails/test_unit/railtie"
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module Climatempoapi
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# Only loads a smaller set of middleware suitable for API only apps.
# Middleware like session, flash, cookies can be added back manually.
# Skip views, helpers and assets when generating a new resource.
config.api_only = true
config.middleware.insert_before 0, "Rack::Cors" do
allow do
origins '*'
resource(
'*',
headers: :any,
methods: [:get, :patch, :put, :delete, :post, :options]
)
end
end
end
end

Na pasta controllers /climateapi/app/controllers/api/v1 criar o arquivo clima_controller.rb

module Api
module V1
    class ClimaController < ApplicationController
def show
@host = 'http://api.openweathermap.org/data/2.5/'
@key = 'SUA_API_KEY'
city = params[:city]
@weather_city = api_request_city_weather(@host, city, @key)
puts @weather_city
render json: @weather_city
end
private
# GET API city weather from Open weather map
def api_request_city_weather(host, city, key)
require 'net/http'
require 'net/https'
require 'open-uri'
require 'json'
url_weather = host + 'weather?q=' + city + '&appid=' + key
uri = URI.parse(url_weather)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
response = http.request(request)
content = JSON.parse(response.body)
return content
end
end
end
end

Na pasta config /climateapi/config alterar o arquivo routes.rb

Rails.application.routes.draw do
namespace 'api' do
namespace 'v1' do
resources :weather, param: :city
end
end
end

Executar o comando no terminal para criar as rotas

C:/workspace/climateapi>rails routes
Controller#Action
api_v1_weather_index GET /api/v1/weather(.:format) api/v1/weather#index
POST /api/v1/weather(.:format) api/v1/weather#create
api_v1_weather GET /api/v1/weather/:city(.:format) api/v1/weather#show
PATCH /api/v1/weather/:city(.:format) api/v1/weather#update
PUT /api/v1/weather/:city(.:format) api/v1/weather#update
DELETE /api/v1/weather/:city(.:format) api/v1/weather#destroy

Em seguida, rodar a API para verificar se os dados em formato JSON foram recuperados da API Rest original.

C:/workspace/climateapi>rails s -b 0.0.0.0 -p 3050

Acessar a URL local no navegador e ver se exibe o resultado: http://localhost:3050/api/v1/weather/Aracaju

{
"coord": {
"lon": -37.07,
"lat": -10.91
},
"weather": [
{
"id": 802,
"main": "Clouds",
"description": "scattered clouds",
"icon": "03n"
}
],
"base": "stations",
"main": {
"temp": 298.15,
"feels_like": 299.58,
"temp_min": 298.15,
"temp_max": 298.15,
"pressure": 1012,
"humidity": 83
},
"visibility": 10000,
"wind": {
"speed": 4.6,
"deg": 100
},
"clouds": {
"all": 40
},
"dt": 1605072214,
"sys": {
"type": 1,
"id": 8322,
"country": "BR",
"sunrise": 1605081293,
"sunset": 1605126599
},
"timezone": -10800,
"id": 3471872,
"name": "Aracaju",
"cod": 200
}

Pronto! Sua API Rest em Ruby on Rails foi criada utilizando outro serviço de API disponível na internet.

Testando uma Rails API com Rspec

Agora que já temos uma Rails API criada, iremos instalar o rspec-rails e outras gems para que seja possível realizar os testes nessa API.

Abrir o arquivo Gemfile na raiz do mesmo projeto climateapi/Gemfile e incluir as seguintes gems na seção :test.

group :development, :test do

gem 'byebug', platform: :mri
gem 'rspec-rails', '~> 4.0.1'
gem 'factory_bot_rails'
end

Entrar na pasta do projeto criado e digitar o comando para instalar as novas bibliotecas do projeto.

C:/workspace/climateapi>bundle install

Em seguida executar o comando para geração da pasta climateapi/spec.

C:/workspace/climateapi>rails generate rspec:install

Entrar nessa pasta e criar um novo arquivo climateapi/spec/clima_spec.rb

require 'rails_helper'
describe "get weather route to Aracaju", :type => :request do
before {get '/api/v1/weather/Aracaju'}
it 'returns weather' do
expect(JSON.parse(response.body)['name']).to eq('Aracaju')
end
it 'returns status code 200' do
expect(response).to have_http_status(:success)
end
end

Em seguida, executar os testes utilizando o comando abaixo.

C:/workspace/climateapi>bundle exec rspec ./spec/weather_spec.rb

Observar que os testes passaram conforme o resultado esperado:

{"coord"=>{"lon"=>-37.07, "lat"=>-10.91}, "weather"=>[{"id"=>802, "main"=>"Clouds", 
"description"=>"scattered clouds", "icon"=>"03n"}], "base"=>"stations", 
"main"=>{"temp"=>298.15, "feels_like"=>299.58, "temp_min"=>298.15, "temp_max"=>298.15, 
"pressure"=>1012, "humidity"=>83}, "visibility"=>10000, "wind"=>{"speed"=>4.6, "deg"=>100}, 
"clouds"=>{"all"=>40}, "dt"=>1605073980, "sys"=>{"type"=>1, "id"=>8322, "country"=>"BR", 
"sunrise"=>1605081293, "sunset"=>1605126599}, "timezone"=>-10800, "id"=>3471872, 
"name"=>"Aracaju", "cod"=>200}


Finished in 1.55 seconds (files took 5.51 seconds to load)
2 examples, 0 failures

Fiz este artigo originalmente no Medium do GTSW:

https://medium.com/gtsw/como-testar-uma-rails-api-com-rspec-596d4ce39988