1
Testes com Python:
Como fazer uma refatoração segura
2
Sobre o apresentador
Valberto Vieira Carneiro
Analista de Tecnologia da Informação - IFPB
Especialista em Qualidade e Testes de Software
3
Roteiro
1. Estudo de caso
2. Motivação
3. Por onde começar?
4. Conceitos
5. Testes
6. Refatoração
7. Dicas
4
Estudo de caso
Módulo de diárias e passagens do Instituto Federal da
Paraíba
5
Fluxo para solicitar diárias e passagens
6
Fluxo para prestar contas da viagem realizada
7
Meu Objetivo
Aplicar melhorias em um sistema que
já está em produção.
Situação
Possui uma lista com novos requisitos
Não possui nenhum teste
Possui manual de usuário
8
Sentimentos
Vamos arrumar a casa
Preciso entender
como esse código
funciona
Será que vai dar
certo?
9
Motivação
Vamos deixar os testes para depois!
Não temos tempo!
Na minha máquina funciona!
10
Testar e refatorar, como fazer?
O que testar e o que não testar?
Qual tipo de testes usar?
11
Por onde começar?
Tenha um objetivo bem definido
Verifique se o módulo possui documentação
Faça um teste exploratório nas principais funcionalidades
Estude sobre refatoração
12
Testar
13
O que é teste de software?
Os testes são realizados com a intenção de descobrir defeitos
em um sistema. [Myres, 2004]
Os testes de software podem ser usados para mostrar a
presença de defeitos, mas nunca para mostrar a ausência
deles. [Dijkstra, 1972]
14
Caixa branca
Código fonte
Testes unitários
Caixa preta
Requisitos
Testes funcionais
Tipos de testes
15
Práticas que poderiam ajudar?
Fonte: http://www.aniche.com.br/tdd/
TDD -
Test Driven Development
- Escrever o teste antes de
codificar
16
Requisitos -
Regras de negócio -
Segurança -
Permissões de usuários -
- Framework
- Métodos nativos
- Requisitos com baixo valor
de negócio**
O que testar e o que não testar?
17
Dicas
- Comece pelo mais simples!
- Evolua os testes gradativamente
- As vezes será necessário reorganizar os testes
- Teste o fluxo principal
- Teste a(s) funcionalidade(s) mais importante(s)
18
Exemplos: teste funcional básico
from django.test import TestCase
class HomologadorTestCase(TestCase):
def test_pagina_inicial(self):
response = self.client.get('/')
self.assertEqual(response.status_code, 200)
self.assertContains(response, u"Título da página")
$ ./manage.py test expedicao
19
Exemplos: afirmações
- assertEqual(a, b) # a == b
- assertNotEqual(a, b) # a <> b
- assertTrue(bool) # True
- assertFalse(bool) # False
- assertRaises(Exception) # raise Exception
- assertIn(a, b) # a in b
- assertNotIn(a, b) # a not in b
- assertGreater(a, b) # a > b
- assertLess(a, b) # a < b
20
Exemplos: teste no Suap
from django.test import TestCase
class SuapTestCase(TestCase):
class ExpedicaoTestCase(SuapTestCase):
class HomologadorTestCase(ExpedicaoTestCase):
def test_pode_ver_aba_homologador(self):
self.logout()
successful = self.client.login(username=self.user.username, password='123')
self.assertEqual(successful, True)
url = "/admin/expedicao/viagemservidor/"
response = self.client.get(url, follow=True)
self.assertContains(response, u"tab_viagens_homologar")
21
from django.test import TestCase
class SuapTestCase(TestCase):
class ExpedicaoTestCase(SuapTestCase):
class HomologadorTestCase(ExpedicaoTestCase):
def test_pode_ver_aba_homologador(self):
self.logout()
successful = self.client.login(username=self.user.username, password='123')
self.assertEqual(successful, True)
url = "/admin/expedicao/viagemservidor/"
response = self.client.get(url, follow=True)
self.assertContains(response, u"tab_viagens_homologar")
Exemplos: teste no Suap
22
from django.test import TestCase
class SuapTestCase(TestCase):
class ExpedicaoTestCase(SuapTestCase):
class HomologadorTestCase(ExpedicaoTestCase):
def acessar_como(self, user):
self.logout()
successful = self.client.login(username=user.username, password='123')
self.assertEqual(successful, True)
def test_pode_ver_aba_homologador(self):
self.acessar_como(self.homologador)
url = "/admin/expedicao/viagemservidor/"
response = self.client.get(url, follow=True)
self.assertContains(response, u"tab_viagens_homologar")
Exemplos: teste no Suap
23
from django.test import TestCase
class SuapTestCase(TestCase):
class ExpedicaoTestCase(SuapTestCase):
class HomologadorTestCase(ExpedicaoTestCase):
def acessar_como(self, user):
self.logout()
successful = self.client.login(username=user.username, password='123')
self.assertEqual(successful, True)
def test_pode_ver_aba_homologador(self):
self.acessar_como(self.homologador)
url = "/admin/expedicao/viagemservidor/"
response = self.client.get(url, follow=True)
self.assertContains(response, u"tab_viagens_homologar")
Exemplos: teste no Suap
24
from django.test import TestCase
class SuapTestCase(TestCase):
class ExpedicaoTestCase(SuapTestCase):
class HomologadorTestCase(ExpedicaoTestCase):
def acessar_como(self, user):
def test_pode_ver_aba_homologador(self):
self.acessar_como(self.homologador)
url = "/admin/expedicao/viagemservidor/"
response = self.client.get(url, follow=True)
self.assertContains(response, u"tab_viagens_homologar")
Exemplos: teste no Suap
25
from django.test import TestCase
class SuapTestCase(TestCase):
class ExpedicaoTestCase(SuapTestCase):
class HomologadorTestCase(ExpedicaoTestCase):
def acessar_como(self, user):
def test_pode_ver_aba_homologador(self):
self.acessar_como(self.homologador)
url = "/admin/expedicao/viagemservidor/"
response = self.client.get(url, follow=True)
self.assertContains(response, u"tab_viagens_homologar")
Exemplos: teste no SuapChangelist {{ app_label }}_{{ model_name }}_changelist
Add {{ app_label }}_{{ model_name }}_add /add
History {{ app_label }}_{{ model_name }}_history /id/history
Delete {{ app_label }}_{{ model_name }}_delete /id/delete
Change {{ app_label }}_{{ model_name }}_change /id
'expedicao_viagemservidor_changelist'
'/admin/expedicao/viagemservidor/'
26
from django.test import TestCase
class SuapTestCase(TestCase):
class ExpedicaoTestCase(SuapTestCase):
class HomologadorTestCase(ExpedicaoTestCase):
def acessar_como(self, user):
def get_changelist_page(cls):
...
def test_pode_ver_aba_homologador(self):
self.acessar_como(self.homologador)
response = self.get_changelist_page(models.ViagemServidor)
self.assertContains(response, u"tab_viagens_homologar")
Exemplos: teste no Suap
27
from django.test import TestCase
class SuapTestCase(TestCase):
class ExpedicaoTestCase(SuapTestCase):
class HomologadorTestCase(ExpedicaoTestCase):
def acessar_como(self, user):
def get_changelist_page(cls):
def test_pode_ver_aba_homologador(self):
self.acessar_como(self.homologador)
response = self.get_changelist_page(models.ViagemServidor)
self.assertContains(response, u"tab_viagens_homologar")
Exemplos: teste no Suap
28
from django.test import TestCase
class SuapTestCase(TestCase):
class ExpedicaoTestCase(SuapTestCase):
class HomologadorTestCase(ExpedicaoTestCase):
def acessar_como(self, user):
def get_changelist_page(cls):
def test_pode_ver_aba_homologador(self):
self.acessar_como(self.homologador)
response = self.get_changelist_page(models.ViagemServidor)
self.assertContains(response, u"tab_viagens_homologar")
# self.logout()
# successful = self.client.login(username=self.user.username, password='123')
# self.assertEqual(successful, True)
# url = "/admin/expedicao/viagemservidor/"
# response = self.client.post(url, follow=True)
# self.assertContains(response, u"tab_viagens_homologar")
Exemplos: teste no Suap
29
Refatorar
30
Refatorar é…
um processo disciplinado de alterar o código de um
sistema sem alterar o seu comportamento observável
buscando melhorar a estrutura interna e minimizando a
chance de introdução de novas falhas.
(Martin Fowler, Kent Beck)
Exige experiência e envolve uma grande
responsabilidade.
31
Refatorar não é…
Alterar o código adicionando novos recursos
Reescrever ou substituir grande partes do código
32
Etapas
1. Detecção de oportunidades de refactoring
2. Decisão do Uso (custos e benefícios)
3. Preparação da avaliação
4. Execução de um dado refactoring
5. Avaliação
33
Etapa 1: Detecção de oportunidades de refactoring
Code smell
é como se aquele trecho de código cheirasse e você sabe
que precisa ser refatorado
Problemas mais comuns
código duplicado | método longo | classes grandes
comandos switch | campo temporário
classe ociosa | comentários
pylint
34
Exemplos: detecção dos pontos de melhoria
# TODO refactory:
- Comentário longo.
- Comentário desnecessário.
- Comentário não condiz com o objetivo do método.
- Imports não utilizados.
- Método/código duplicado comum.utils.get_funcionario.
- Linhas com mais de 80 caracteres.
- Método muito extenso.
- Número mágico.
- Nome muito grande para uma variável (23 caracteres).
35
Exemplos: detecção dos pontos de melhoria
# TODO refactory:
- Comentário longo.
- Comentário desnecessário.
- Comentário não condiz com o objetivo do método.
- Imports não utilizados.
- Método/código duplicado comum.utils.get_funcionario.
- Linhas com mais de 80 caracteres.
- Método muito extenso.
- Número mágico.
- Nome muito grande para uma variável (23 caracteres).
# Cria o relatório referente a esta viagem
relatorio = RelatorioViagem(viagem=viagem)
relatorio.save()
36
Exemplos: detecção dos pontos de melhoria
# TODO refactory:
- Comentário longo.
- Comentário desnecessário.
- Comentário não condiz com o objetivo do método.
- Imports não utilizados.
- Método/código duplicado comum.utils.get_funcionario.
- Linhas com mais de 80 caracteres.
- Método muito extenso.
- Número mágico.
- Nome muito grande para uma variável (23 caracteres).
if (data.isoweekday() >= 6):
37
Exemplos: detecção dos pontos de melhoria
# TODO refactory:
- Comentário longo.
- Comentário desnecessário.
- Comentário não condiz com o objetivo do método.
- Imports não utilizados.
- Método/código duplicado comum.utils.get_funcionario.
- Linhas com mais de 80 caracteres.
- Método muito extenso.
- Número mágico.
- Nome muito grande para uma variável (23 caracteres).
SABADO, DOMINGO = 6, 7
if data.isoweekday() in [SABADO, DOMINGO]:
38
Exemplos: detecção dos pontos de melhoria
# TODO refactory:
- Aquivo não tem limitador de extensão nem de tamanho.
- Extrair consulta para um método.
- Nomenclatura não exite mais.
- Condições complexas demais. Substituir por método:
is_empty(nome_campo).
- Substituir condições negativas por uma afirmativas.
39
Exemplos: detecção dos pontos de melhoria
# TODO refactory:
- Aquivo não tem limitador de extensão nem de tamanho.
- Extrair consulta para um método.
- Nomenclatura não exite mais.
- Condições complexas demais. Substituir por método:
is_empty(nome_campo).
- Substituir condições negativas por uma afirmativas.
arquivo = models.FileField(
upload_to='/comprovantes/',
verbose_name=u'Comprovante')
40
Exemplos: detecção dos pontos de melhoria
# TODO refactory:
- Aquivo não tem limitador de extensão nem de tamanho.
- Extrair consulta para um método.
- Nomenclatura não exite mais.
- Condições complexas demais. Substituir por método:
is_empty(nome_campo).
- Substituir condições negativas por uma afirmativas.
arquivo = models.FileField(
upload_to='/comprovantes/',
verbose_name=u'Comprovante',
help_text=u'Tamanho máximo 2MB.',
validators=[FileValidator()])
41
Exemplos: detecção dos pontos de melhoria
# TODO refactory:
- Aquivo não tem limitador de extensão nem de tamanho.
- Extrair consulta para um método.
- Nomenclatura não exite mais.
- Condições complexas demais. Substituir por método:
is_empty(nome_campo).
- Substituir condições negativas por uma afirmativas.
historico = HistoricoSolicitacao.objects.
filter(viagem=self).
order_by('-data').
all()[0]
historico = self.historicos.latest('data')
42
Exemplos: detecção dos pontos de melhoria
# TODO refactory:
- Aquivo não tem limitador de extensão nem de tamanho.
- Extrair consulta para um método.
- Nomenclatura não exite mais.
- Condições complexas demais. Substituir por método:
is_empty(nome_campo).
- Substituir condições negativas por uma afirmativas.
def ultimo_historico():
return self.historicos.latest('data')
historico = ultimo_historico()
43
Etapa 2: Decisão do Uso (custos e benefícios)
Custos e benefícios
Tempo e esforço necessários valerão a pena?
Decisão não automatizada
Código duplicado:
Extrair Método, Extrair Classe, Subir Método na
Hierarquia ou Substituir Algoritmo
44
Etapa 3: Preparação da avaliação
Desenvolver testes
Garantir que o comportamento do sistema seja mantido
Decidir qual tipo de testes
Testes funcionais
Caixa preta
45
Dicas
Crie grupos de funções que deseja testar
- perfil de usuário (testar acesso e negação de acesso)
- fluxo de negócio
- regras de negócio (validações)
46
Exemplos: Preparação da avaliação
class ExpedicaoTestCase(SuapTestCase):
Testes Tempo
class AdministradorTestCase(ExpedicaoTestCase): | 4 | 00:00:38 |
class ExecutorTestCase(ExpedicaoTestCase): | 4 | 00:00:02 |
class HomologadorTestCase(ExpedicaoTestCase): | 1 | 00:00:00 |
class AutorizadorUOTestCase(ExpedicaoTestCase): | 2 | 00:00:01 |
class ChefeTestCase(ExpedicaoTestCase): | 5 | 00:00:03 |
class SubstitutoTestCase(ExpedicaoTestCase): | 4 | 00:00:03 |
class ViagemServidorTestCase(ExpedicaoTestCase): | 14 | 00:00:11 |
class RelatorioViagemTestCase(ExpedicaoTestCase):| 7 | 00:00:09 |
TOTAL: 41 | 00:01:12 |
Cobertura 72%
$ pip install coverage
47
Etapa 4: Execução de um dado refactoring
Aplicar as refatorações
Objetivo é eliminar o code smell
Qual o momento certo?
Atividade contínua, integrada ao desenvolvimento:
- Acrescentar uma função
- Consertar uma falha
- Revisar o código
48
Exemplos: Aplicar refatorações
def relatorio_detail(request, id):
title = u'Relatório do Servidor'
usuario = request.user
try:
relatorio = RelatorioViagem.objects.get(id=id)
except RelatorioViagem.DoesNotExist:
return HttpResponseBadRequest(u'O relatório não existe!')
if not (eh_dono_viagem(request, relatorio.viagem.id) or 
eh_ordenador(request) or 
eh_executor(request) or 
usuario.eh_chefe_do_setor(usuario.setor)):
raise PermissionDenied
return locals()
49
Exemplos: Aplicar refatorações
def relatorio_detail(request, id):
title = u'Relatório do Servidor'
usuario = request.user
try:
relatorio = RelatorioViagem.objects.get(id=id)
except RelatorioViagem.DoesNotExist:
return HttpResponseBadRequest(u'O relatório não existe!')
if not (eh_dono_viagem(request, relatorio.viagem.id) or 
eh_ordenador(request) or 
eh_executor(request) or 
usuario.eh_chefe_do_setor(usuario.servidor.setor)):
raise PermissionDenied
return locals()
relatorio = get_object_or_404(RelatorioViagem, pk=id)
50
Exemplos: Aplicar refatorações
def relatorio_detail(request, id):
title = u'Relatório do Servidor'
usuario = request.user
relatorio = get_object_or_404(RelatorioViagem, pk=id)
if not (eh_dono_viagem(request, relatorio.viagem.id) or 
eh_ordenador(request) or 
eh_executor(request) or 
usuario.eh_chefe_do_setor(usuario.setor)):
raise PermissionDenied
return locals()
51
Exemplos: Aplicar refatorações
def relatorio_detail(request, id):
title = u'Relatório do Servidor'
usuario = request.user
relatorio = get_object_or_404(RelatorioViagem, pk=id)
if not (eh_dono_viagem(request, relatorio.viagem.id) or 
eh_ordenador(request) or 
eh_executor(request) or 
usuario.eh_chefe_do_setor(usuario.setor)):
raise PermissionDenied
return locals()
regra = regras.RelatorioViagemRegras(relatorio)
if not regra.pode_ver(request.user):
raise PermissionDenied
52
Exemplos: Aplicar refatorações
def relatorio_detail(request, id):
title = u'Relatório do Servidor'
relatorio = get_object_or_404(RelatorioViagem, pk=id)
regra = regras.RelatorioViagemRegras(relatorio)
if not regra.pode_ver(request.user):
raise PermissionDenied
return locals()
Etapa 5: Avaliação
O comportamento é o mesmo?
Analisar resultado dos testes
Realizar análise cognitiva
Buscar novo code smell
53
54
Fonte: CARNEIRO, 2003
55
Perguntas
56
Referências
- CARNEIRO, Glauco de F. Usando medição de código fonte para refactoring. Abril de 2003. 123 p. Dissertação (Mestrado
Profissional em Redes de Computadores) - Universidade Salvador, Salvador, 2003.
- Dijkstra, E. W. "The Humble Programmer". Communications of the ACM 15 (10): 859–866, 1972.
- Entendendo Testes de Software https://willianjusten.com.br/entendendo-testes-de-software/
- FOWLER, Martin et al. Refatoração: Aperfeiçoando o Projeto de Código Existente. trad.Acauan Fernandes – Porto Alegre:
Bookman, 2004.
- Improve Your Python: Understanding Unit Testing https://jeffknupp.com/blog/
- List for code-quality tools related to Python https://mail.python.org/mailman/listinfo/code-quality
- Myres , G. F. “The Art of Software Testing”. Ed. John Wiley & Sons, Inc. New Jersey, 2004.
- O que é e o que não é refatoração – de acordo com Kent Beck e Martin Fowler
https://dzone.com/articles/what-refactoring-and-what-it-0
- Os 10 princípios dos Testes de Software http://gtsw.blogspot.com.br/2007/12/os-princpios-dos-testes-de-software.html
- Refactoring Patterns https://dzone.com/refcardz/refactoring-patterns
- Review of Python Static Analysis Tools http://blog.codacy.com/2016/01/08/review-of-python-static-analysis-tools/
- Start Here: Introductions to Python Testing Frameworks http://pythontesting.net/start-here/
- Testes e Refatoração http://pt.slideshare.net/jeveaux/testes-e-refatorao-presentation-622966
- Writing unit tests in Python: How do I start?
http://stackoverflow.com/questions/3371255/writing-unit-tests-in-python-how-do-i-start

Testes com python: como fazer uma refatoração segura

  • 1.
    1 Testes com Python: Comofazer uma refatoração segura
  • 2.
    2 Sobre o apresentador ValbertoVieira Carneiro Analista de Tecnologia da Informação - IFPB Especialista em Qualidade e Testes de Software
  • 3.
    3 Roteiro 1. Estudo decaso 2. Motivação 3. Por onde começar? 4. Conceitos 5. Testes 6. Refatoração 7. Dicas
  • 4.
    4 Estudo de caso Módulode diárias e passagens do Instituto Federal da Paraíba
  • 5.
    5 Fluxo para solicitardiárias e passagens
  • 6.
    6 Fluxo para prestarcontas da viagem realizada
  • 7.
    7 Meu Objetivo Aplicar melhoriasem um sistema que já está em produção. Situação Possui uma lista com novos requisitos Não possui nenhum teste Possui manual de usuário
  • 8.
    8 Sentimentos Vamos arrumar acasa Preciso entender como esse código funciona Será que vai dar certo?
  • 9.
    9 Motivação Vamos deixar ostestes para depois! Não temos tempo! Na minha máquina funciona!
  • 10.
    10 Testar e refatorar,como fazer? O que testar e o que não testar? Qual tipo de testes usar?
  • 11.
    11 Por onde começar? Tenhaum objetivo bem definido Verifique se o módulo possui documentação Faça um teste exploratório nas principais funcionalidades Estude sobre refatoração
  • 12.
  • 13.
    13 O que éteste de software? Os testes são realizados com a intenção de descobrir defeitos em um sistema. [Myres, 2004] Os testes de software podem ser usados para mostrar a presença de defeitos, mas nunca para mostrar a ausência deles. [Dijkstra, 1972]
  • 14.
    14 Caixa branca Código fonte Testesunitários Caixa preta Requisitos Testes funcionais Tipos de testes
  • 15.
    15 Práticas que poderiamajudar? Fonte: http://www.aniche.com.br/tdd/ TDD - Test Driven Development - Escrever o teste antes de codificar
  • 16.
    16 Requisitos - Regras denegócio - Segurança - Permissões de usuários - - Framework - Métodos nativos - Requisitos com baixo valor de negócio** O que testar e o que não testar?
  • 17.
    17 Dicas - Comece pelomais simples! - Evolua os testes gradativamente - As vezes será necessário reorganizar os testes - Teste o fluxo principal - Teste a(s) funcionalidade(s) mais importante(s)
  • 18.
    18 Exemplos: teste funcionalbásico from django.test import TestCase class HomologadorTestCase(TestCase): def test_pagina_inicial(self): response = self.client.get('/') self.assertEqual(response.status_code, 200) self.assertContains(response, u"Título da página") $ ./manage.py test expedicao
  • 19.
    19 Exemplos: afirmações - assertEqual(a,b) # a == b - assertNotEqual(a, b) # a <> b - assertTrue(bool) # True - assertFalse(bool) # False - assertRaises(Exception) # raise Exception - assertIn(a, b) # a in b - assertNotIn(a, b) # a not in b - assertGreater(a, b) # a > b - assertLess(a, b) # a < b
  • 20.
    20 Exemplos: teste noSuap from django.test import TestCase class SuapTestCase(TestCase): class ExpedicaoTestCase(SuapTestCase): class HomologadorTestCase(ExpedicaoTestCase): def test_pode_ver_aba_homologador(self): self.logout() successful = self.client.login(username=self.user.username, password='123') self.assertEqual(successful, True) url = "/admin/expedicao/viagemservidor/" response = self.client.get(url, follow=True) self.assertContains(response, u"tab_viagens_homologar")
  • 21.
    21 from django.test importTestCase class SuapTestCase(TestCase): class ExpedicaoTestCase(SuapTestCase): class HomologadorTestCase(ExpedicaoTestCase): def test_pode_ver_aba_homologador(self): self.logout() successful = self.client.login(username=self.user.username, password='123') self.assertEqual(successful, True) url = "/admin/expedicao/viagemservidor/" response = self.client.get(url, follow=True) self.assertContains(response, u"tab_viagens_homologar") Exemplos: teste no Suap
  • 22.
    22 from django.test importTestCase class SuapTestCase(TestCase): class ExpedicaoTestCase(SuapTestCase): class HomologadorTestCase(ExpedicaoTestCase): def acessar_como(self, user): self.logout() successful = self.client.login(username=user.username, password='123') self.assertEqual(successful, True) def test_pode_ver_aba_homologador(self): self.acessar_como(self.homologador) url = "/admin/expedicao/viagemservidor/" response = self.client.get(url, follow=True) self.assertContains(response, u"tab_viagens_homologar") Exemplos: teste no Suap
  • 23.
    23 from django.test importTestCase class SuapTestCase(TestCase): class ExpedicaoTestCase(SuapTestCase): class HomologadorTestCase(ExpedicaoTestCase): def acessar_como(self, user): self.logout() successful = self.client.login(username=user.username, password='123') self.assertEqual(successful, True) def test_pode_ver_aba_homologador(self): self.acessar_como(self.homologador) url = "/admin/expedicao/viagemservidor/" response = self.client.get(url, follow=True) self.assertContains(response, u"tab_viagens_homologar") Exemplos: teste no Suap
  • 24.
    24 from django.test importTestCase class SuapTestCase(TestCase): class ExpedicaoTestCase(SuapTestCase): class HomologadorTestCase(ExpedicaoTestCase): def acessar_como(self, user): def test_pode_ver_aba_homologador(self): self.acessar_como(self.homologador) url = "/admin/expedicao/viagemservidor/" response = self.client.get(url, follow=True) self.assertContains(response, u"tab_viagens_homologar") Exemplos: teste no Suap
  • 25.
    25 from django.test importTestCase class SuapTestCase(TestCase): class ExpedicaoTestCase(SuapTestCase): class HomologadorTestCase(ExpedicaoTestCase): def acessar_como(self, user): def test_pode_ver_aba_homologador(self): self.acessar_como(self.homologador) url = "/admin/expedicao/viagemservidor/" response = self.client.get(url, follow=True) self.assertContains(response, u"tab_viagens_homologar") Exemplos: teste no SuapChangelist {{ app_label }}_{{ model_name }}_changelist Add {{ app_label }}_{{ model_name }}_add /add History {{ app_label }}_{{ model_name }}_history /id/history Delete {{ app_label }}_{{ model_name }}_delete /id/delete Change {{ app_label }}_{{ model_name }}_change /id 'expedicao_viagemservidor_changelist' '/admin/expedicao/viagemservidor/'
  • 26.
    26 from django.test importTestCase class SuapTestCase(TestCase): class ExpedicaoTestCase(SuapTestCase): class HomologadorTestCase(ExpedicaoTestCase): def acessar_como(self, user): def get_changelist_page(cls): ... def test_pode_ver_aba_homologador(self): self.acessar_como(self.homologador) response = self.get_changelist_page(models.ViagemServidor) self.assertContains(response, u"tab_viagens_homologar") Exemplos: teste no Suap
  • 27.
    27 from django.test importTestCase class SuapTestCase(TestCase): class ExpedicaoTestCase(SuapTestCase): class HomologadorTestCase(ExpedicaoTestCase): def acessar_como(self, user): def get_changelist_page(cls): def test_pode_ver_aba_homologador(self): self.acessar_como(self.homologador) response = self.get_changelist_page(models.ViagemServidor) self.assertContains(response, u"tab_viagens_homologar") Exemplos: teste no Suap
  • 28.
    28 from django.test importTestCase class SuapTestCase(TestCase): class ExpedicaoTestCase(SuapTestCase): class HomologadorTestCase(ExpedicaoTestCase): def acessar_como(self, user): def get_changelist_page(cls): def test_pode_ver_aba_homologador(self): self.acessar_como(self.homologador) response = self.get_changelist_page(models.ViagemServidor) self.assertContains(response, u"tab_viagens_homologar") # self.logout() # successful = self.client.login(username=self.user.username, password='123') # self.assertEqual(successful, True) # url = "/admin/expedicao/viagemservidor/" # response = self.client.post(url, follow=True) # self.assertContains(response, u"tab_viagens_homologar") Exemplos: teste no Suap
  • 29.
  • 30.
    30 Refatorar é… um processodisciplinado de alterar o código de um sistema sem alterar o seu comportamento observável buscando melhorar a estrutura interna e minimizando a chance de introdução de novas falhas. (Martin Fowler, Kent Beck) Exige experiência e envolve uma grande responsabilidade.
  • 31.
    31 Refatorar não é… Alteraro código adicionando novos recursos Reescrever ou substituir grande partes do código
  • 32.
    32 Etapas 1. Detecção deoportunidades de refactoring 2. Decisão do Uso (custos e benefícios) 3. Preparação da avaliação 4. Execução de um dado refactoring 5. Avaliação
  • 33.
    33 Etapa 1: Detecçãode oportunidades de refactoring Code smell é como se aquele trecho de código cheirasse e você sabe que precisa ser refatorado Problemas mais comuns código duplicado | método longo | classes grandes comandos switch | campo temporário classe ociosa | comentários pylint
  • 34.
    34 Exemplos: detecção dospontos de melhoria # TODO refactory: - Comentário longo. - Comentário desnecessário. - Comentário não condiz com o objetivo do método. - Imports não utilizados. - Método/código duplicado comum.utils.get_funcionario. - Linhas com mais de 80 caracteres. - Método muito extenso. - Número mágico. - Nome muito grande para uma variável (23 caracteres).
  • 35.
    35 Exemplos: detecção dospontos de melhoria # TODO refactory: - Comentário longo. - Comentário desnecessário. - Comentário não condiz com o objetivo do método. - Imports não utilizados. - Método/código duplicado comum.utils.get_funcionario. - Linhas com mais de 80 caracteres. - Método muito extenso. - Número mágico. - Nome muito grande para uma variável (23 caracteres). # Cria o relatório referente a esta viagem relatorio = RelatorioViagem(viagem=viagem) relatorio.save()
  • 36.
    36 Exemplos: detecção dospontos de melhoria # TODO refactory: - Comentário longo. - Comentário desnecessário. - Comentário não condiz com o objetivo do método. - Imports não utilizados. - Método/código duplicado comum.utils.get_funcionario. - Linhas com mais de 80 caracteres. - Método muito extenso. - Número mágico. - Nome muito grande para uma variável (23 caracteres). if (data.isoweekday() >= 6):
  • 37.
    37 Exemplos: detecção dospontos de melhoria # TODO refactory: - Comentário longo. - Comentário desnecessário. - Comentário não condiz com o objetivo do método. - Imports não utilizados. - Método/código duplicado comum.utils.get_funcionario. - Linhas com mais de 80 caracteres. - Método muito extenso. - Número mágico. - Nome muito grande para uma variável (23 caracteres). SABADO, DOMINGO = 6, 7 if data.isoweekday() in [SABADO, DOMINGO]:
  • 38.
    38 Exemplos: detecção dospontos de melhoria # TODO refactory: - Aquivo não tem limitador de extensão nem de tamanho. - Extrair consulta para um método. - Nomenclatura não exite mais. - Condições complexas demais. Substituir por método: is_empty(nome_campo). - Substituir condições negativas por uma afirmativas.
  • 39.
    39 Exemplos: detecção dospontos de melhoria # TODO refactory: - Aquivo não tem limitador de extensão nem de tamanho. - Extrair consulta para um método. - Nomenclatura não exite mais. - Condições complexas demais. Substituir por método: is_empty(nome_campo). - Substituir condições negativas por uma afirmativas. arquivo = models.FileField( upload_to='/comprovantes/', verbose_name=u'Comprovante')
  • 40.
    40 Exemplos: detecção dospontos de melhoria # TODO refactory: - Aquivo não tem limitador de extensão nem de tamanho. - Extrair consulta para um método. - Nomenclatura não exite mais. - Condições complexas demais. Substituir por método: is_empty(nome_campo). - Substituir condições negativas por uma afirmativas. arquivo = models.FileField( upload_to='/comprovantes/', verbose_name=u'Comprovante', help_text=u'Tamanho máximo 2MB.', validators=[FileValidator()])
  • 41.
    41 Exemplos: detecção dospontos de melhoria # TODO refactory: - Aquivo não tem limitador de extensão nem de tamanho. - Extrair consulta para um método. - Nomenclatura não exite mais. - Condições complexas demais. Substituir por método: is_empty(nome_campo). - Substituir condições negativas por uma afirmativas. historico = HistoricoSolicitacao.objects. filter(viagem=self). order_by('-data'). all()[0] historico = self.historicos.latest('data')
  • 42.
    42 Exemplos: detecção dospontos de melhoria # TODO refactory: - Aquivo não tem limitador de extensão nem de tamanho. - Extrair consulta para um método. - Nomenclatura não exite mais. - Condições complexas demais. Substituir por método: is_empty(nome_campo). - Substituir condições negativas por uma afirmativas. def ultimo_historico(): return self.historicos.latest('data') historico = ultimo_historico()
  • 43.
    43 Etapa 2: Decisãodo Uso (custos e benefícios) Custos e benefícios Tempo e esforço necessários valerão a pena? Decisão não automatizada Código duplicado: Extrair Método, Extrair Classe, Subir Método na Hierarquia ou Substituir Algoritmo
  • 44.
    44 Etapa 3: Preparaçãoda avaliação Desenvolver testes Garantir que o comportamento do sistema seja mantido Decidir qual tipo de testes Testes funcionais Caixa preta
  • 45.
    45 Dicas Crie grupos defunções que deseja testar - perfil de usuário (testar acesso e negação de acesso) - fluxo de negócio - regras de negócio (validações)
  • 46.
    46 Exemplos: Preparação daavaliação class ExpedicaoTestCase(SuapTestCase): Testes Tempo class AdministradorTestCase(ExpedicaoTestCase): | 4 | 00:00:38 | class ExecutorTestCase(ExpedicaoTestCase): | 4 | 00:00:02 | class HomologadorTestCase(ExpedicaoTestCase): | 1 | 00:00:00 | class AutorizadorUOTestCase(ExpedicaoTestCase): | 2 | 00:00:01 | class ChefeTestCase(ExpedicaoTestCase): | 5 | 00:00:03 | class SubstitutoTestCase(ExpedicaoTestCase): | 4 | 00:00:03 | class ViagemServidorTestCase(ExpedicaoTestCase): | 14 | 00:00:11 | class RelatorioViagemTestCase(ExpedicaoTestCase):| 7 | 00:00:09 | TOTAL: 41 | 00:01:12 | Cobertura 72% $ pip install coverage
  • 47.
    47 Etapa 4: Execuçãode um dado refactoring Aplicar as refatorações Objetivo é eliminar o code smell Qual o momento certo? Atividade contínua, integrada ao desenvolvimento: - Acrescentar uma função - Consertar uma falha - Revisar o código
  • 48.
    48 Exemplos: Aplicar refatorações defrelatorio_detail(request, id): title = u'Relatório do Servidor' usuario = request.user try: relatorio = RelatorioViagem.objects.get(id=id) except RelatorioViagem.DoesNotExist: return HttpResponseBadRequest(u'O relatório não existe!') if not (eh_dono_viagem(request, relatorio.viagem.id) or eh_ordenador(request) or eh_executor(request) or usuario.eh_chefe_do_setor(usuario.setor)): raise PermissionDenied return locals()
  • 49.
    49 Exemplos: Aplicar refatorações defrelatorio_detail(request, id): title = u'Relatório do Servidor' usuario = request.user try: relatorio = RelatorioViagem.objects.get(id=id) except RelatorioViagem.DoesNotExist: return HttpResponseBadRequest(u'O relatório não existe!') if not (eh_dono_viagem(request, relatorio.viagem.id) or eh_ordenador(request) or eh_executor(request) or usuario.eh_chefe_do_setor(usuario.servidor.setor)): raise PermissionDenied return locals() relatorio = get_object_or_404(RelatorioViagem, pk=id)
  • 50.
    50 Exemplos: Aplicar refatorações defrelatorio_detail(request, id): title = u'Relatório do Servidor' usuario = request.user relatorio = get_object_or_404(RelatorioViagem, pk=id) if not (eh_dono_viagem(request, relatorio.viagem.id) or eh_ordenador(request) or eh_executor(request) or usuario.eh_chefe_do_setor(usuario.setor)): raise PermissionDenied return locals()
  • 51.
    51 Exemplos: Aplicar refatorações defrelatorio_detail(request, id): title = u'Relatório do Servidor' usuario = request.user relatorio = get_object_or_404(RelatorioViagem, pk=id) if not (eh_dono_viagem(request, relatorio.viagem.id) or eh_ordenador(request) or eh_executor(request) or usuario.eh_chefe_do_setor(usuario.setor)): raise PermissionDenied return locals() regra = regras.RelatorioViagemRegras(relatorio) if not regra.pode_ver(request.user): raise PermissionDenied
  • 52.
    52 Exemplos: Aplicar refatorações defrelatorio_detail(request, id): title = u'Relatório do Servidor' relatorio = get_object_or_404(RelatorioViagem, pk=id) regra = regras.RelatorioViagemRegras(relatorio) if not regra.pode_ver(request.user): raise PermissionDenied return locals()
  • 53.
    Etapa 5: Avaliação Ocomportamento é o mesmo? Analisar resultado dos testes Realizar análise cognitiva Buscar novo code smell 53
  • 54.
  • 55.
  • 56.
    56 Referências - CARNEIRO, Glaucode F. Usando medição de código fonte para refactoring. Abril de 2003. 123 p. Dissertação (Mestrado Profissional em Redes de Computadores) - Universidade Salvador, Salvador, 2003. - Dijkstra, E. W. "The Humble Programmer". Communications of the ACM 15 (10): 859–866, 1972. - Entendendo Testes de Software https://willianjusten.com.br/entendendo-testes-de-software/ - FOWLER, Martin et al. Refatoração: Aperfeiçoando o Projeto de Código Existente. trad.Acauan Fernandes – Porto Alegre: Bookman, 2004. - Improve Your Python: Understanding Unit Testing https://jeffknupp.com/blog/ - List for code-quality tools related to Python https://mail.python.org/mailman/listinfo/code-quality - Myres , G. F. “The Art of Software Testing”. Ed. John Wiley & Sons, Inc. New Jersey, 2004. - O que é e o que não é refatoração – de acordo com Kent Beck e Martin Fowler https://dzone.com/articles/what-refactoring-and-what-it-0 - Os 10 princípios dos Testes de Software http://gtsw.blogspot.com.br/2007/12/os-princpios-dos-testes-de-software.html - Refactoring Patterns https://dzone.com/refcardz/refactoring-patterns - Review of Python Static Analysis Tools http://blog.codacy.com/2016/01/08/review-of-python-static-analysis-tools/ - Start Here: Introductions to Python Testing Frameworks http://pythontesting.net/start-here/ - Testes e Refatoração http://pt.slideshare.net/jeveaux/testes-e-refatorao-presentation-622966 - Writing unit tests in Python: How do I start? http://stackoverflow.com/questions/3371255/writing-unit-tests-in-python-how-do-i-start