Talk feito no 2º meetup de testes de Marília/SP realizado no InnovaSpace da UNIVEM no dia 07/11/2018.
Nele, contamos um pouco sobre como automatizamos testes "client-side" de APIs REST.
7. voltando aos conceitos...
REST API
arquitetura para serviços web
abstração em cima do protocolo HTTP
operações definidas com base no HTTP
HTTP
protocolo de comunicação das internetes
8. voltando aos conceitos...
Protocolo HTTP:
URL (Universal Resource Location)
host, path, query string
Requisição HTTP
verb, URL, header, body
Resposta HTTP
status code, header, body
9. o que vou precisar?
Um “executor” de testes (ex: rspec)
Uma biblioteca de assertions (ex: rspec-expectations)
Client HTTP (ex: Net::Http nativo do ruby)
Parser de JSON (ex: json nativo do ruby)
Validador de JSON (ex: json-schema, hash_validator)
Validar respostas (objeto com a resposta completa)
10. como quero escrever os testes?
priorizar legibilidade e simplicidade
menos DRY (don’t repeat yourself)
mais verboso
menos mágica
separar código de acesso à API do código de teste
11. como quero escrever os testes?
estilo specification:
describe ‘thing’
it ‘do something’ { expect(thing).to do_something }
it ‘does not do this’ { expect(thing).not_to do_this }
it ‘has some of that’ { expect(thing).to have_that }
12. como quero escrever os testes?
Padrão AAA (3A)
Arrange (ou Setup)
Act (ou Exercise)
Assert (ou Verify)
13. como quero escrever os testes?
seguir um roteiro:
Arrange: Montar a requisição (verb, URL, header, body)
Act: Enviar a requisição / receber resposta
Assert: Validar resposta (status code, header, body)
15. misturando tudo
Expectations
definição das estruturas de retorno esperadas
campos retornados na resposta e seus tipos de dados
testes de contrato
ex:
{ nome: ‘string’, idade: ‘integer’, nascimento: ‘date’ }
16. misturando tudo
Testes
subject é a entidade (foco do teste)
um ‘describe’ por entidade
um ‘context’ por operação
before/after cria/deleta dependências
isolamento!
21. exemplo
Teste (spec)
describe 'User API' do
subject(:user) { User.new }
context 'POST /user (create user)' do
it 'creates a new user' do
# arrange
user.body = { name: 'João', email: 'joao@mail.com' }
# act
response = user.create
# assert
expect(response.status_code).to eq '201 Created'
expect(response.body).to have_structure_like user.expected_create
expect(response.body[:message]).to eq 'Usuário criado com sucesso!'
expect(response.body[:name]).to eq 'João'
expect(response.body[:email]).to eq 'joao@mail.com'
end
22. exemplo
outro teste
it 'does not create user when email is invalid' do
# arrange
user.body = { name: 'João', email: 'invalidmail' }
# act
response = user.create
# assert
expect(response.status_code).to eq '400 Bad Request'
expect(response.body[:error]).to eq 'e-mail inválido'
end
end # end context
23. exemplo
context 'GET /user/login' do
before(:context) { create_user }
after(:context) { delete_user }
it 'do user login' do
# arrange
user.body = { email: 'joao@mail.com', password: 'senha123' }
# act
response = user.login
# assert
expect(response.status_code).to eq '200 OK'
expect(response.body).to have_structure_like user.expected_login
expect(response.body[:message]).to eq 'Bem vindo João!'
expect(response.body[:name]).to eq 'João'
expect(response.body[:session]).not_to be_empty
end
end
end # end describe