Globalcode – Open4education
Garantindo a qualidade da sua API
REST com Behave
Alex S. Garzão
Projetista de Software
Yuri Z. Pinheiro
Analista de Qualidade
ZAP Imóveis
www.linkedin.com/in/alexgarzao/ www.linkedin.com/in/yurizp
Globalcode – Open4education
Agenda
• Nosso contexto
• Projeto, desafios, problemas e soluções
• O que é BDD
• O que é Behave
• Nossa proposta
• Demonstração
• Resultados
• Lições aprendidas
• Próximos passos
Globalcode – Open4education
Vamos nos conhecer
• Testes automatizados. Quem aqui utiliza?
• BDD. Quem conhece? Quem utiliza?
• Behave. Quem conhece? Quem utiliza?
Globalcode – Open4education
Nosso contexto no ZAP
• Desenvolvemos API RESTful
• Python
• Django
• MySQL
Globalcode – Open4education
Primeiros desafios
• Regras de negócio instáveis
• Definição do escopo em andamento
• Entendimento do projeto não era claro
• Novas tecnologias na empresa
Globalcode – Open4education
O que isso ocasionou?
• Baixa qualidade de código (Bugs a rodo)
• Retrabalho do time
• Time desmotivado
Globalcode – Open4education
Qual a solução?
• Testes, obviamente
• Começamos com testes manuais
• Mas isso não escala
• Tester virou gargalo da equipe
• Vamos automatizar :-)
Globalcode – Open4education
Em busca de soluções
● Aplicação em Python
○ É possível, mas partiríamos do zero :-/
● Curl
○ Fácil para testes pontuais
● Postman
○ Legal, mas a automação dele é trabalhosa
● Robot framework
○ Técnico demais
● Lettuce
○ Legal, mas foi descontinuado
● Behave
Globalcode – Open4education
O que é o BDD?
• Técnica de desenvolvimento ágil
• Encoraja interação entre técnicos e “não técnicos”
• Foco no negócio, e não nos detalhes técnicos
• Exemplos descrevem o comportamento da
aplicação
• São executáveis (documentação viva)
• São testes regressivos
Globalcode – Open4education
Fluxo com BDD
Fonte: http://www.qualister.com.br/blog/o-que-e-atdd---acceptance-test-driven-development
Globalcode – Open4education
O que é o Behave?
• Utilizado para a prática de automação de testes
• Open source
• Suporte para BDD em Python
• Permite a escrita de cenários de teste
• Linguagem próxima a “natural”
Globalcode – Open4education
Exemplo Behave - Calcular fatorial
Funcionalidade: Calcular o fatorial
Cenário: Fatorial de 0
Dado eu tenho o número 0
Quando eu calculo este fatorial
Então eu vejo o número 1
Cenário: Fatorial de 2
Dado eu tenho o número 2
Quando eu calculo este fatorial
Então eu vejo o número 2
Cenário: Fatorial de 4
Dado eu tenho o número 4
Quando eu calculo este fatorial
Então eu vejo o número 24
Globalcode – Open4education
Funcionalidade: Calcular o fatorial
Cenário: Fatorial de 0
Dado eu tenho o número 0
Quando eu calculo este fatorial
Então eu vejo o número 1
@given(u'eu tenho o número {number}')
def step_impl(context, number):
context.number = int(number)
@when(u'eu calculo este fatorial')
def step_impl(context):
context.number = factorial(context.number)
@then(u'eu vejo o número {expected}')
def step_impl(context, expected):
expected = int(expected)
assert context.number == expected
Globalcode – Open4education
• Métodos de uma API Rest
• Exemplo: Rota para cadastro de imóveis
• Endpoint: https://api.meusite.com/imoveis
• JSON: {
proprietario: "fulano de tal",
endereco: "Rua A, 520",
valor: 450000
}
O que queríamos testar?
Globalcode – Open4education
Oh shit!
• Behave é uma ferramenta genérica
• Não entende API RESTful
• HTTP? JSON? GET/POST/PUT/DELETE?
• Endpoint? Request? HTTP status code?
Globalcode – Open4education
Nossa proposta...
• Ferramenta open source
• Utilizando o Behave
• Permite a escrita de testes automatizados
• Entende o que é uma API RESTful
• Cenários de testes são executáveis
• Escritos em português
Globalcode – Open4education
Tentativa 1 - O início de tudo...
Globalcode – Open4education
Esquema do Cenário: Como usuário tento cadastrar imóveis
Dado que eu quero cadastrar um imóvel
E o proprietário é <nome> e o endereço é <endereço> e o
valor é <valor>
Quando eu tento cadastrar o imóvel
Então eu recebo o código 200
Exemplos: Dados válidos para imóveis
| nome | endereço | valor |
| Proprietário 01 | Rua A POA RS | 1000.00 |
| Proprietário 02 | Rua B POA RS | 2000.00 |
• Step confuso de entender
• Steps muito específicos
• Reutilização engessada
• A cada novo step, uma nova implementação
Globalcode – Open4education
Tentativa 2
Globalcode – Open4education
Esquema do Cenário: Como usuário tento cadastrar imóveis
Dado que eu quero cadastrar um imóvel
E o proprietário é <nome>
E o endereço é <endereço>
E o valor é <valor>
Quando eu tento cadastrar o imóvel
Então eu recebo o código 200
Exemplos: Dados válidos para imóveis
| nome | endereço | valor |
| Proprietário 01 | Rua A POA RS | 1000.00 |
| Proprietário 02 | Rua B POA RS | 2000.00 |
• Maior reutilização :-)
• Melhor legibilidade
• A cada novo step uma nova implementação :-(
Globalcode – Open4education
Hoje - Steps genéricos
Globalcode – Open4education
Esquema do Cenário: Como usuário quero cadastrar imóveis
Dado que eu quero cadastrar um imóvel
E o campo nome do proprietário é <nome>
E o campo endereço do imóvel é <endereço>
E o campo valor do imóvel é <valor>
Quando eu tento cadastrar o imóvel
Então eu recebo o status que indica imóvel criado
Exemplos: Dados válidos para imóveis
| nome | endereço | valor |
| Proprietário 01 | Rua A POA RS | 1000.00 |
| Proprietário 02 | Rua B POA RS | 2000.00 |
• Não temos mais steps específicos por campo
• Utilizamos alias (apelidos) para campos, códigos de status,
endpoints, ...
Globalcode – Open4education
Como são definidos os “alias”?
Globalcode – Open4education
Esquema do Cenário: Mapeando os campos do JSON
Dado que eu quero mapear os campos do JSON
E o campo <alias> é <tipo> e corresponde a <campo>
Quando eu tento mapear os campos
Então nenhuma falha ocorre
Exemplos: Campos do método de imóveis
| alias | tipo | campo |
| nome do proprietário | string | proprietario |
| endereço do imóvel | string | endereco |
| valor do imóvel | number | valor |
• É fácil criar novos campos
• Fazer manutenção (trocar tipo, nome no JSON, …)
• Independência na criação de cenários
• Técnicos e não técnicos
Globalcode – Open4education
E listas?
Globalcode – Open4education
Cenário: Como usuário quero listar meus imóveis
Dado que eu quero listar os meus imóveis
Quando eu busco a lista de imóveis
Então eu recebo o status que indica requisição válida
E obtenho a lista de dados abaixo
| nome do proprietário | endereço do imóvel |
| Proprietário 01 | Rua A POA RS |
| Proprietário 02 | Rua B POA RS |
• Validamos tipagem
• Validamos só os campos necessários
• Onde está o valor?
Globalcode – Open4education
E dados não previsíveis?
Globalcode – Open4education
Cenário: Como usuário quero listar meus imóveis
Dado que eu quero listar os meus imóveis
Quando eu busco a lista de imóveis
Então eu recebo o status que indica requisição válida
E obtenho a lista de dados abaixo
| nome do proprietário | data e hora criação |
| Proprietário 01 | <nao nulo> |
| Proprietário 02 | <nao nulo> |
• Temos outros tipos de validações
• <nao vazio>
• <nulo>
• <vazio> ou “”
• Não temos validações complexas
• > 20, < 100, ...
Globalcode – Open4education
Como enviamos nulo e vazio em
requisições?
Globalcode – Open4education
Esquema do Cenário: Como usuário quero cadastrar imóveis
Dado que eu quero cadastrar um imóvel
E o campo nome do proprietário é <nome>
E o campo endereço do imóvel é <endereço>
E o campo valor do imóvel é <valor>
Quando eu tento cadastrar o imóvel
Então eu recebo o status que indica imóvel criado
Exemplos: Dados válidos para imóveis
| nome | endereço | valor |
| Proprietário 01 | Rua A POA RS | <nulo> |
| Proprietário 02 | <vazio> | 250000 |
| Proprietário 03 | “ A B C ” | 350000 |
Globalcode – Open4education
E quando precisamos de dados
variáveis?
Globalcode – Open4education
Esquema do Cenário: Como usuário quero cadastrar imóveis
Dado que eu quero cadastrar um imóvel
E o campo nome do proprietário é <nome>
E o campo endereço do imóvel é <endereço>
E o campo valor do imóvel é <valor>
Quando eu tento cadastrar o imóvel
Então eu recebo o status que indica imóvel criado
E guardo o retorno em <variável>
Exemplos: Dados válidos para imóveis
| nome | endereço | valor | variável |
| Proprietário 01 | Rua A POA RS | 150000 | imóvel 01 |
| Proprietário 02 | Rua B POA RS | 250000 | imóvel 02 |
• Permite reutilização de dados não previsíveis em outros
cenários
Globalcode – Open4education
Cenário: Como usuário quero listar meus imóveis
Dado que eu quero listar os meus imóveis
Quando eu busco a lista de imóveis
Então eu recebo o status que indica requisição válida
E obtenho a lista de dados abaixo
| nome do proprietário | endereço do imóvel |
| $imóvel 01.nome do proprietário | Rua A POA RS |
| $imóvel 02.nome do proprietário | Rua B POA RS |
• Variáveis podem ser utilizadas em qualquer step
• Podemos acessar qualquer campo do JSON
Globalcode – Open4education
Demonstração
Globalcode – Open4education
Resultados
• Fomos
• De poucos testes manuais para 90% de cobertura
(testes automatizados)
• Ganho de tempo
• Temos testes sendo executados a todo momento
• Para cada novo bug temos um cenário de teste
• Facilidade em desenvolver novos testes
Globalcode – Open4education
Resultados
• Confiança na qualidade
• Confiança para realizar alterações críticas
• Qualquer pessoa, técnica ou não, consegue
desenvolver novos cenários
Globalcode – Open4education
Lições aprendidas
• Tempo para girar a roda é alto
• Dependência de API’s externas? Mock
• Setup dos dados no início dos testes
• Criar o banco, inserir dados de configuração, ...
• Não usar dados fictícios
• Rodar os testes em homologação
• Em produção é um plus
• Feature deve ser independente
• Cenário independente melhor ainda!
Globalcode – Open4education
Próximos passos
• Pacote instalável via pip
• Disseminar o BDD
• Mande sua sugestão :-)
Globalcode – Open4education
Referências
• Livro BDD in Action:
https://www.manning.com/books/bdd-in-action
• Projeto: https://github.com/alexgarzao/victory
• Behave: http://pythonhosted.org/behave/
Globalcode – Open4education
Perguntas?

Garantindo a qualidade da sua API REST com Behave

  • 1.
    Globalcode – Open4education Garantindoa qualidade da sua API REST com Behave Alex S. Garzão Projetista de Software Yuri Z. Pinheiro Analista de Qualidade ZAP Imóveis www.linkedin.com/in/alexgarzao/ www.linkedin.com/in/yurizp
  • 2.
    Globalcode – Open4education Agenda •Nosso contexto • Projeto, desafios, problemas e soluções • O que é BDD • O que é Behave • Nossa proposta • Demonstração • Resultados • Lições aprendidas • Próximos passos
  • 3.
    Globalcode – Open4education Vamosnos conhecer • Testes automatizados. Quem aqui utiliza? • BDD. Quem conhece? Quem utiliza? • Behave. Quem conhece? Quem utiliza?
  • 4.
    Globalcode – Open4education Nossocontexto no ZAP • Desenvolvemos API RESTful • Python • Django • MySQL
  • 5.
    Globalcode – Open4education Primeirosdesafios • Regras de negócio instáveis • Definição do escopo em andamento • Entendimento do projeto não era claro • Novas tecnologias na empresa
  • 6.
    Globalcode – Open4education Oque isso ocasionou? • Baixa qualidade de código (Bugs a rodo) • Retrabalho do time • Time desmotivado
  • 7.
    Globalcode – Open4education Quala solução? • Testes, obviamente • Começamos com testes manuais • Mas isso não escala • Tester virou gargalo da equipe • Vamos automatizar :-)
  • 8.
    Globalcode – Open4education Embusca de soluções ● Aplicação em Python ○ É possível, mas partiríamos do zero :-/ ● Curl ○ Fácil para testes pontuais ● Postman ○ Legal, mas a automação dele é trabalhosa ● Robot framework ○ Técnico demais ● Lettuce ○ Legal, mas foi descontinuado ● Behave
  • 9.
    Globalcode – Open4education Oque é o BDD? • Técnica de desenvolvimento ágil • Encoraja interação entre técnicos e “não técnicos” • Foco no negócio, e não nos detalhes técnicos • Exemplos descrevem o comportamento da aplicação • São executáveis (documentação viva) • São testes regressivos
  • 10.
    Globalcode – Open4education Fluxocom BDD Fonte: http://www.qualister.com.br/blog/o-que-e-atdd---acceptance-test-driven-development
  • 11.
    Globalcode – Open4education Oque é o Behave? • Utilizado para a prática de automação de testes • Open source • Suporte para BDD em Python • Permite a escrita de cenários de teste • Linguagem próxima a “natural”
  • 12.
    Globalcode – Open4education ExemploBehave - Calcular fatorial Funcionalidade: Calcular o fatorial Cenário: Fatorial de 0 Dado eu tenho o número 0 Quando eu calculo este fatorial Então eu vejo o número 1 Cenário: Fatorial de 2 Dado eu tenho o número 2 Quando eu calculo este fatorial Então eu vejo o número 2 Cenário: Fatorial de 4 Dado eu tenho o número 4 Quando eu calculo este fatorial Então eu vejo o número 24
  • 13.
    Globalcode – Open4education Funcionalidade:Calcular o fatorial Cenário: Fatorial de 0 Dado eu tenho o número 0 Quando eu calculo este fatorial Então eu vejo o número 1 @given(u'eu tenho o número {number}') def step_impl(context, number): context.number = int(number) @when(u'eu calculo este fatorial') def step_impl(context): context.number = factorial(context.number) @then(u'eu vejo o número {expected}') def step_impl(context, expected): expected = int(expected) assert context.number == expected
  • 14.
    Globalcode – Open4education •Métodos de uma API Rest • Exemplo: Rota para cadastro de imóveis • Endpoint: https://api.meusite.com/imoveis • JSON: { proprietario: "fulano de tal", endereco: "Rua A, 520", valor: 450000 } O que queríamos testar?
  • 15.
    Globalcode – Open4education Ohshit! • Behave é uma ferramenta genérica • Não entende API RESTful • HTTP? JSON? GET/POST/PUT/DELETE? • Endpoint? Request? HTTP status code?
  • 16.
    Globalcode – Open4education Nossaproposta... • Ferramenta open source • Utilizando o Behave • Permite a escrita de testes automatizados • Entende o que é uma API RESTful • Cenários de testes são executáveis • Escritos em português
  • 17.
  • 18.
    Globalcode – Open4education Esquemado Cenário: Como usuário tento cadastrar imóveis Dado que eu quero cadastrar um imóvel E o proprietário é <nome> e o endereço é <endereço> e o valor é <valor> Quando eu tento cadastrar o imóvel Então eu recebo o código 200 Exemplos: Dados válidos para imóveis | nome | endereço | valor | | Proprietário 01 | Rua A POA RS | 1000.00 | | Proprietário 02 | Rua B POA RS | 2000.00 | • Step confuso de entender • Steps muito específicos • Reutilização engessada • A cada novo step, uma nova implementação
  • 19.
  • 20.
    Globalcode – Open4education Esquemado Cenário: Como usuário tento cadastrar imóveis Dado que eu quero cadastrar um imóvel E o proprietário é <nome> E o endereço é <endereço> E o valor é <valor> Quando eu tento cadastrar o imóvel Então eu recebo o código 200 Exemplos: Dados válidos para imóveis | nome | endereço | valor | | Proprietário 01 | Rua A POA RS | 1000.00 | | Proprietário 02 | Rua B POA RS | 2000.00 | • Maior reutilização :-) • Melhor legibilidade • A cada novo step uma nova implementação :-(
  • 21.
  • 22.
    Globalcode – Open4education Esquemado Cenário: Como usuário quero cadastrar imóveis Dado que eu quero cadastrar um imóvel E o campo nome do proprietário é <nome> E o campo endereço do imóvel é <endereço> E o campo valor do imóvel é <valor> Quando eu tento cadastrar o imóvel Então eu recebo o status que indica imóvel criado Exemplos: Dados válidos para imóveis | nome | endereço | valor | | Proprietário 01 | Rua A POA RS | 1000.00 | | Proprietário 02 | Rua B POA RS | 2000.00 | • Não temos mais steps específicos por campo • Utilizamos alias (apelidos) para campos, códigos de status, endpoints, ...
  • 23.
    Globalcode – Open4education Comosão definidos os “alias”?
  • 24.
    Globalcode – Open4education Esquemado Cenário: Mapeando os campos do JSON Dado que eu quero mapear os campos do JSON E o campo <alias> é <tipo> e corresponde a <campo> Quando eu tento mapear os campos Então nenhuma falha ocorre Exemplos: Campos do método de imóveis | alias | tipo | campo | | nome do proprietário | string | proprietario | | endereço do imóvel | string | endereco | | valor do imóvel | number | valor | • É fácil criar novos campos • Fazer manutenção (trocar tipo, nome no JSON, …) • Independência na criação de cenários • Técnicos e não técnicos
  • 25.
  • 26.
    Globalcode – Open4education Cenário:Como usuário quero listar meus imóveis Dado que eu quero listar os meus imóveis Quando eu busco a lista de imóveis Então eu recebo o status que indica requisição válida E obtenho a lista de dados abaixo | nome do proprietário | endereço do imóvel | | Proprietário 01 | Rua A POA RS | | Proprietário 02 | Rua B POA RS | • Validamos tipagem • Validamos só os campos necessários • Onde está o valor?
  • 27.
    Globalcode – Open4education Edados não previsíveis?
  • 28.
    Globalcode – Open4education Cenário:Como usuário quero listar meus imóveis Dado que eu quero listar os meus imóveis Quando eu busco a lista de imóveis Então eu recebo o status que indica requisição válida E obtenho a lista de dados abaixo | nome do proprietário | data e hora criação | | Proprietário 01 | <nao nulo> | | Proprietário 02 | <nao nulo> | • Temos outros tipos de validações • <nao vazio> • <nulo> • <vazio> ou “” • Não temos validações complexas • > 20, < 100, ...
  • 29.
    Globalcode – Open4education Comoenviamos nulo e vazio em requisições?
  • 30.
    Globalcode – Open4education Esquemado Cenário: Como usuário quero cadastrar imóveis Dado que eu quero cadastrar um imóvel E o campo nome do proprietário é <nome> E o campo endereço do imóvel é <endereço> E o campo valor do imóvel é <valor> Quando eu tento cadastrar o imóvel Então eu recebo o status que indica imóvel criado Exemplos: Dados válidos para imóveis | nome | endereço | valor | | Proprietário 01 | Rua A POA RS | <nulo> | | Proprietário 02 | <vazio> | 250000 | | Proprietário 03 | “ A B C ” | 350000 |
  • 31.
    Globalcode – Open4education Equando precisamos de dados variáveis?
  • 32.
    Globalcode – Open4education Esquemado Cenário: Como usuário quero cadastrar imóveis Dado que eu quero cadastrar um imóvel E o campo nome do proprietário é <nome> E o campo endereço do imóvel é <endereço> E o campo valor do imóvel é <valor> Quando eu tento cadastrar o imóvel Então eu recebo o status que indica imóvel criado E guardo o retorno em <variável> Exemplos: Dados válidos para imóveis | nome | endereço | valor | variável | | Proprietário 01 | Rua A POA RS | 150000 | imóvel 01 | | Proprietário 02 | Rua B POA RS | 250000 | imóvel 02 | • Permite reutilização de dados não previsíveis em outros cenários
  • 33.
    Globalcode – Open4education Cenário:Como usuário quero listar meus imóveis Dado que eu quero listar os meus imóveis Quando eu busco a lista de imóveis Então eu recebo o status que indica requisição válida E obtenho a lista de dados abaixo | nome do proprietário | endereço do imóvel | | $imóvel 01.nome do proprietário | Rua A POA RS | | $imóvel 02.nome do proprietário | Rua B POA RS | • Variáveis podem ser utilizadas em qualquer step • Podemos acessar qualquer campo do JSON
  • 34.
  • 35.
    Globalcode – Open4education Resultados •Fomos • De poucos testes manuais para 90% de cobertura (testes automatizados) • Ganho de tempo • Temos testes sendo executados a todo momento • Para cada novo bug temos um cenário de teste • Facilidade em desenvolver novos testes
  • 36.
    Globalcode – Open4education Resultados •Confiança na qualidade • Confiança para realizar alterações críticas • Qualquer pessoa, técnica ou não, consegue desenvolver novos cenários
  • 37.
    Globalcode – Open4education Liçõesaprendidas • Tempo para girar a roda é alto • Dependência de API’s externas? Mock • Setup dos dados no início dos testes • Criar o banco, inserir dados de configuração, ... • Não usar dados fictícios • Rodar os testes em homologação • Em produção é um plus • Feature deve ser independente • Cenário independente melhor ainda!
  • 38.
    Globalcode – Open4education Próximospassos • Pacote instalável via pip • Disseminar o BDD • Mande sua sugestão :-)
  • 39.
    Globalcode – Open4education Referências •Livro BDD in Action: https://www.manning.com/books/bdd-in-action • Projeto: https://github.com/alexgarzao/victory • Behave: http://pythonhosted.org/behave/
  • 40.