VCR em aplicação Rails

O VCR é um ferramenta que tem como principal objetivo simplificar testes de integração e reduzir a dependência de recursos externos, como APIs de terceiros.

O VCR, ou Versatile Cassette Recorder, é uma ferramenta valiosa em aplicações Ruby on Rails, que tem como principal objetivo simplificar testes de integração e reduzir a dependência de recursos externos, como APIs de terceiros. Sua funcionalidade principal consiste em gravar solicitações HTTP realizadas durante testes e reproduzir essas respostas em futuros testes, eliminando a necessidade de interações reais com a API a cada execução de teste, o que muita vezes resulta em cobranças pelo uso da API.

Principais Funções do VCR

  • Gravação e Reprodução de Requisições, então basicamente os VCRs são responsáveis por gravar uma requisição durante a execução de um teste, armazenando essas interações em “cassetes” para posteriormente pode reutiliza-los, evitando que a API seja consumida várias vezes para o mesmo teste.
  • Isolamento de Testes, como uma resposta de um requisição foi gravada em um cassete, o VCR isola os testes do código real da API, permitindo que os desenvolvedores se concentrem mais na lógica específica da aplicação sem depender da disponibilidade ou confiabilidade da API externa, lembrando que pra isso pelo menos uma vez a requisição deve ser gravada no cassete.
  • Eficiência e Velocidade, como as respostas da API são pré-gravadas, os testes podem ser executados mais rapidamente, uma vez que não há atrasos causados por chamadas de rede. Isso é super útil quando executamos testes em ambientes de integração contínua ou durante o desenvolvimento local, onde não precisamos mais no preocupar se a API está funcinando ou não.
  • Facilidade de Manutenção, gravar e reproduzir cassetes simplifica a manutenção dos testes no futuro. Se a API ou os endpoints mudarem por exemplo, você só precisa regravar os cassetes afetados em vez de ajustar manualmente todos os testes ou ainda se tiver problemas de conectividade seus testes não serão afetados.
  • Economia de Custos, evita custos associados a chamadas frequentes à API, especialmente durante o desenvolvimento e execução de testes, ao reproduzir respostas gravadas em vez de fazer solicitações reais.

Exemplo:

Vamos considerar um cenário em que uma aplicação Rails faz uma chamada a uma API de previsão do tempo. Usando o VCR, podemos gravar a resposta da API e reproduzi-la em futuros testes.

  • Instalação: Adicione a gem VCR dentro do seu gemfile e rode bundle install
gem 'vcr'
  • Configuração: Configure VCR no seu ambiente de teste
require 'vcr'

VCR.configure do |config|
  config.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
  config.hook_into :webmock
end
  • Adicione nos seus testes
require 'rails_helper'
require 'vcr'

RSpec.describe MeteorologiaService do
  describe "#pegar_climatempo" do
    let(:user) { User.create(nome: "Julia") }
    let(:cidade) { 'Rio de Janeiro'}

    it 'obtém a previsão do tempo' do
      VCR.use_cassette('climatempo') do
        climatempo = MeteorologiaService.new(cidade: cidade).pegar_climatempo

        expect(climatempo).to_not be_empty
      end
    end
  end
end
  • Resultado: Após esse código, assim seria um exemplo de como ficaria salvo o cassete, lembrando que ele é salvo dentro de um arquivo yaml geralmente no caminho: spec/fixtures/vcr_cassettes/climatempo.yml
http_interactions:
- request:
    method: get
    uri: https://api.weather.com/forecast?city=city
    body: ''
    headers:
      Accept:
      - application/json
  response:
    status:
      code: 200
      message: OK
    headers:
      Content-Type:
      - application/json
    body: '{"temperature": 25, "condition": "Sunny"}'
  recorded_at: 2024-02-07T12:00:00.000Z
  recorded_with: VCR 6.0.0

recorded_with: VCR 6.0.0

Algumas dicas valiosas para configurar seu VCR

A gem VCR é utilizada para realizarmos os testes integrados na nossa aplicação rails, nos permetindo automatizar o processo de stub das requisições web. Então, como vimos anteriormente a gente vai poder executar nossos testes com mais velocidade sem depender da disponibilidade da API.

Contudo, quando nossos testes começam a ficar muito grandes, temos que ter alguns cuidados para evitar futuros problemas.

1- Gerar nomes dos cassetes automaticamente: quando estamos trabalhando com o rspec podemos marcar cada cenário que irá utilizar vcr com o símbolo :vcr

describe AlgumaApiExterna do
  it 'cria um produto', :vcr do
  # seu teste aqui
  end
end

# e dentro da sua config voce deve adicionar
VCR.configure do |c|
  c.configure_rspec_metadata!
end

Ao final seu vcr irá ter o nome do seu contexto, nesse caso spec/fixtures/vcr_cassettes/AlgumaApiExterna/cria_um_produto.yml

2- Modos de Gravação: em alguns cenários, será necessário mudar o comportamento do um cassete.Por exemplo eu posso querer regravar um cassete, gravar uma nova iteração ou não gravar nenhum.

  • :once: Grava as interações HTTP uma vez e as reproduz em execuções de novos testes.
  • :new_episodes: Grava novas interações e reproduz as existentes.
  • :none: Não grava novas interações; sempre reproduz as existentes.
  • :all: Usado temporariamente para forçar o cassete a ser regravado ou simplesmente registrar todas as solicitações HTTP.
  • :record_on_error: Requisição é gravada quando um erro é levantado.

Um cassete por padrão usa o modo de gravação :once, o que significa que a primeira vez que uma requisição é feita durante um teste, ele é gravado em um arquivo novo do tipo yml. Em execuções futuras do mesmo teste, o VCR reproduzirá as respostas gravadas em vez de fazer uma chamada de rede real.

VCR.configure do |config|
  config.default_cassette_options = { record: :new_episodes }
end

ou

it 'obtém a previsão do tempo' do
  VCR.use_cassette('climatempo'), record: :new_episodes  do
    climatempo = MeteorologiaService.new(cidade: cidade).pegar_climatempo

    expect(climatempo).to_not be_empty
  end
end

3- Proteja suas chaves públicas dentro do seu cassete

A seguir trago algumas formas para proteger suas credenciais quando estamos trabalhando com VCR, pois é muito comum disponibilizamos alguns dados nos cassetes.

3.1. Utilize variáveis de ambiente: Uma boa prática é amazenar suas credencias em variáveis de ambiente, assim podemos criar diferentes valores para ambientes de desenvolvimento, teste e produçao.

config.api_key = ENV['API_KEY']

3.2. Não versione credenciais: Evite ao máximo versionar diretamnete as credencias mo sistema de controle de versao. É recomendado adicionar o arquivo de configuração ou as variáveis de ambiente na lista de itens ignorados( usando o arquivo .gitignore como exemplo).

config/credentials.yml.enc

3.3 Cifre as credencias: Voce pode utilizar o comando rails credential:edit para editar suas credenciais de forma segura.

api_key: 'sua_api_key_cifrada'

3.4 Filtre dados sensíveis: Voce pode filtrar informações sensíveis dos cassetes para evitar a exposição

VCR.configure do |config|
  config.filter_sensitive_data('<API_KEY>') { ENV['API_KEY'] }
end

Testes frameworks

CUCUMBER: podemos utilizar os cassetes com o cucumber em dois caminhos básicos:

  • Utilizar VCR.use_cassette em uma definição de passo (step definition).
  • Utilizar um bloco VCR.cucumber_tags para indicar ao VCR o uso de um cassette para um cenário marcado (tagged scenario).

Em um arquivo de suporte do Cucumber (por exemplo, features/support/vcr.rb), é possível configurar as tags do Cucumber e associá-las aos cassetes específicos usando o VCR. Assim estamos criando cassetes nomeados de acordo com as tags ou nome dos cenários, facilitando a organização e identificação dos registros de testes automatizados. Exemplos:

  VCR.cucumber_tags do |t|
    t.tag  '@tag1'
    t.tags '@tag2', '@tag3'

    t.tag  '@tag3', :cassette => :options
    t.tags '@tag4', '@tag5', :cassette => :options
    t.tag  '@vcr', :use_scenario_name => true
  end
  1. t.tag '@tag1': significa que os cassetes do VCR serão aplicadas apenas a cenários de teste que tenham a tag @tag1.
  2. t.tags '@tag2', '@tag3': Semelhante ao caso anterior, os cenários de teste marcados com essas duas tags usarão as cassetes do VCR.
  3. t.tag @tag3 : Associa uma opção de cassete chamada ‘:options’ a ela para personalizar as configurações da cassete a esta tag.
  4. t.tags '@tag4', '@tag5', :cassette => :options Similar ao caso anterior, define as tags @tag4 e @tag5 para usar a cassete ‘:options’.
  5. t.tag '@vcr', :use_scenario_name => true Define a tag @vcr e especifica que o VCR deve usar o nome do cenário como parte do nome da cassete. Isso é útil para garantir que exista apenas um cassete para cada tag, pois cada cenário pode ter uma cassete separado.

TESTE UNITÁRIO: Para poder usar o VCR com o Test::Unit, basta envolver o corpo de qualquer teste com o VCR.use_cassete .

describe Mercos::ItemTabelaDeVenda do
  describe "#all" do
    let(:integracao_mercos) { create(:integracao_mercos, token: 'token-teste') }

    it "retorna todos os itens cadastrados" do
      VCR.use_cassette("Mercos/todos_itens_tabela_de_venda") do
        itens_tabelas_de_vendas = Mercos::ItemTabelaDeVenda.new(integracao_mercos: integracao_mercos)

        response = itens_tabelas_de_vendas.all

        expect(response.body.size).to eq 73
        expect(response.total).to eq 73
      end
    end
end

Conclusão

A integração do VCR em testes Ruby On Rails é essencial para melhorar a eficiência e confiabilidade de seus testes. Ao isolar sua iteração HTTP em cassetes gravados, o VCR elimina a dependência de serviços externos durante o teste, garantindo um ambiente sempre constante onde não necessita ficar indo em APIs externas toda vez, reduzindo seus custos e tempo. Além disso, o VCR nos permite personalizar algumas configurações, como modos de gravações, correspondências de requisições e manipulação de dados sensíveis. O uso do VCR é recomendado para equipes de desenvolvimento que buscam melhorar a eficiência, a confiabilidade e a consistência de seus testes.

Referências

0 Comentário